POJ 3311 Hie with the Pie

链接

题意:

  n+1个点,求从0开始,走完所有的点,再回到0号点的最小距离。

思路

  状压dp。首先Floyd预处理出任意两个点之间的距离。dp[s][i]表示走过的点的状态是s,其中到达i点的最小距离(i点属于走过的点,即s状态下的点)。当然s是二进制数1表示走过,0表示为走过。

  那么dp[s][i]就可以到达非s状态的点j,j点是不属于s状态的点,dp[s|(1<<(j-1))][j] = min(dp[s][i]+dis[i][j]);这是一个“推”的转移方程。

  ”拉“:dp[s][i] = min(dp[s^(1<<(i-1))][j]+dis[j][i])。

代码

”推“的写法:

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<cmath>
 6 
 7 using namespace std;
 8 
 9 const int N = 15;
10 int dp[35000][N],dis[N][N];
11 int n;
12 
13 inline int read() {
14     int x = 0,f = 1;char ch = getchar();
15     for (; !isdigit(ch); ch=getchar()) if(ch=='-') f=-1;
16     for (; isdigit(ch); ch=getchar()) x = x*10+ch-'0';
17     return x * f;
18 }
19 void Floyd() {
20     for (int k=0; k<=n; ++k) 
21         for (int i=0; i<=n; ++i) 
22             for (int j=0; j<=n; ++j) 
23                 dis[i][j] = min(dis[i][j],dis[i][k] + dis[k][j]);
24 }
25 int main() {
26     while (~scanf("%d",&n) != EOF && n) {
27         memset(dis,0x3f,sizeof(dis));
28         memset(dp,0x3f,sizeof(dp));
29         for (int i=0; i<=n; ++i) 
30             for (int j=0; j<=n; ++j) 
31                 dis[i][j] = read();
32         Floyd();
33         int t = (1 << n) - 1;
34         dp[0][0] = 0;
35         for (int i=1; i<=n; ++i) dp[(1<<(i-1))][i] = dis[0][i];
36         for (int s=1; s<=t; ++s) 
37             for (int i=1; i<=n; ++i) {
38                 if (s&(1<<(i-1))==0) continue;
39                 for (int j=1; j<=n; ++j) {
40                     if (s&(1<<(j-1))) continue;
41                     dp[s|(1<<(j-1))][j] = min(dp[s|(1<<(j-1))][j],dp[s][i]+dis[i][j]);
42                 }    
43             }
44         
45         int ans = 1e9;
46         for (int i=1; i<=n; ++i) {
47             ans = min(ans,dp[t][i]+dis[i][0]);
48         }
49         cout << ans << "\n";
50     }
51     return 0;
52 }
View Code

"拉”的写法

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<cmath>
 6 
 7 using namespace std;
 8 
 9 const int N = 15;
10 int dp[35000][N],dis[N][N];
11 int n;
12 
13 inline int read() {
14     int x = 0,f = 1;char ch = getchar();
15     for (; !isdigit(ch); ch=getchar()) if(ch=='-') f=-1;
16     for (; isdigit(ch); ch=getchar()) x = x*10+ch-'0';
17     return x * f;
18 }
19 void Floyd() {
20     for (int k=0; k<=n; ++k) 
21         for (int i=0; i<=n; ++i) 
22             for (int j=0; j<=n; ++j) 
23                 dis[i][j] = min(dis[i][j],dis[i][k] + dis[k][j]);
24 }
25 int main() {
26     while (~scanf("%d",&n) != EOF && n) {
27         memset(dis,0x3f,sizeof(dis));
28         memset(dp,0x3f,sizeof(dp));
29         for (int i=0; i<=n; ++i) 
30             for (int j=0; j<=n; ++j) 
31                 dis[i][j] = read();
32         Floyd();
33         int t = (1 << n) - 1;
34         for (int s=0; s<=t; ++s) 
35             for (int i=1; i<=n; ++i) {
36                 if (s&(1<<(i-1))==0) continue;
37                 if (s == (1<<(i-1))) dp[s][i] = dis[0][i];
38                 else {
39                     for (int j=1; j<=n; ++j) {
40                         if (s&(1<<(j-1))==0) continue;
41                         dp[s][i] = min(dp[s][i],dp[s^(1<<(i-1))][j]+dis[j][i]);
42                     }
43                 }    
44             }
45         
46         int ans = 1e9;
47         for (int i=1; i<=n; ++i) {
48             ans = min(ans,dp[t][i]+dis[i][0]);
49         }
50         cout << ans << "\n";
51     }
52     return 0;
53 }
View Code

猜你喜欢

转载自www.cnblogs.com/mjtcn/p/8965799.html