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 }
"拉”的写法
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 }