题是看了这位的博客之后理解的,只不过我是又加了点简单的注释。
链接:http://blog.csdn.net/chinaczy/article/details/5890768
我还加了一些注释代码,对于新手的我,看起来可能更方便些吧,顺便说下快捷键
先选中要操作的行,ctrl+shift+c 是注释 ctrl+shift+x是解注释(cb的快捷键)
/* Floyd + 状态压缩DP 题意是有N个城市(1~N)和一个PIZZA店(0),要求一条回路,从0出发,又回到0,而且距离最短 也就是TSP(旅行商)问题,首先不难想到用FLOYD先求出任意2点的距离dis[i][j] 接着枚举所有状态,用11位二进制表示10个城市和pizza店,1表示经过,0表示没有经过 定义状态DP(S,i)表示在S状态下,到达城市I的最优值 接着状态转移方程:DP(S,i) = min{DP(S^(1<<i-1),k) + dis[k][j],DP(S,i)},其中S^(1<<i-1)表示未到达城市i的所有状态,1<=k<=n 对于全1的状态,即S = (1<<n)-1则表示经过所有城市的状态,最终还需要回到PIZZA店0 那么最终答案就是min{DP(S,i) + dis[i][0]} TSP是NP困难问题,所以地图必须要小,本题是10,所以也可以根据这个想到floyd,(时间复杂度n^3)和状压dp (用二进制存10位,且只有2个状态,走过,没走过) */ #include <map> #include <set> #include <list> #include <cmath> #include <queue> #include <stack> #include <vector> #include <cstdio> #include <string> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define INF 100000000 using namespace std; int dis[12][12]; int dp[1<<11][12]; int n,ans,_min; int main() { #ifndef ONLINE_JUDGE freopen("C:\Users\Zmy\Desktop\in.txt","r",stdin);//这应该修改下重定向的文件路径 // freopen("C:\Users\Zmy\Desktop\out.txt","w",stdout); #endif // ONLINE_JUDGE while(scanf("%d",&n) && n) { /**< 输入 */ for(int i = 0; i <= n; ++i) for(int j = 0; j <= n; ++j) scanf("%d",&dis[i][j]); // puts("before"); // for(int i = 0; i <= n; ++i) // { // for(int j = 0; j <= n; ++j) // printf("%3d ",dis[i][j]); // puts(""); // } /**< 这段用弗洛伊德求出了从i点到各个j点的最短距离 存在了dis中,即更新了dis */ for(int k = 0; k <= n; ++k) for(int i = 0; i <= n; ++i) for(int j = 0; j <= n; ++j) if(dis[i][k] + dis[k][j] < dis[i][j]) dis[i][j] = dis[i][k] + dis[k][j]; // puts("after"); // for(int i = 0; i <= n; ++i) // { // for(int j = 0; j <= n; ++j) // printf("%3d ",dis[i][j]); // puts(""); // } for(int S = 0; S < (1<<n); ++S) //枚举所有状态,用位运算表示 for(int i = 1; i <= n; ++i) { if(S & (1<<(i-1)))//状态S中已经过城市i { /**< 注意:DP的边界是这句话,好牛逼!! */ if(S == (1<<(i-1))) dp[S][i] = dis[0][i];//状态S只经过城市I,最优解自然是从0出发到i的dis,这也是DP的边界 //如果S有经过多个城市 else { dp[S][i] = INF; //枚举不是城市I的其他城市 for(int j = 1; j <= n; ++j) { //在没经过城市I的状态中,寻找合适的中间点J使得距离更短,和FLOYD一样 if(S & (1<<(j-1)) && j != i) dp[S][i] = min(dp[S^(1<<(i-1))][j] + dis[j][i],dp[S][i]); } } } } ans = dp[(1<<n)-1][1] + dis[1][0]; for(int i = 2; i <= n; ++i) if(dp[(1<<n)-1][i] + dis[i][0] < ans) ans = dp[(1<<n)-1][i] + dis[i][0]; printf("%d ",ans); } return 0; }