点击打开链接
解题思路:这道题目和TSP问题很相似,唯一不同的是同一个点可以重复走几次。。。。
这道题目只有16个顶点,所以很容易想到状态压缩dp,dp[i][j]表示到达顶点i时的状态为j的最小花费,那么状态方程也很容易推理出来dp[i][j] = min(dp[k][j-1<<i]+map[i][k]);这里注意,由于每一个点可以到达多次,所以这里的map要先用Floyd算法来处理,否则就会出现用还未更新的状态去更新当前的状态,这样很明显两个状态都无法保证是最优的,第一次WA就是卡在这里,后面看了别人的解题报告,才明白了Floyd算法在这里的重要性。。。
AC:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int inf = 0x3f3f3f3f; int n,m; int dp[20][1<<17],map[20][20]; int main() { int t; scanf("%d",&t); while(t--) { int w,u,v,bit; scanf("%d%d",&n,&m); memset(map,inf,sizeof(map)); memset(dp,inf,sizeof(dp)); for(int i = 1; i <= m; i++) { scanf("%d%d%d",&u,&v,&w); map[u][v] = min(map[u][v],w); map[v][u] = map[u][v]; } for(int k = 1; k <= n; k++) for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) map[i][j] = min(map[i][j],map[i][k] + map[k][j]); bit = 1<<n; dp[1][1] = 0; for(int j = 1; j < bit; j++) for(int k = 1; k <= n; k++) for(int i = 1; i <= n; i++) { if(map[i][k] == inf) continue; int tmp = 1 << (i-1); if(j & tmp) { if(dp[k][j] != inf) { dp[i][j] = min(dp[i][j],dp[k][j] + map[i][k]); } if(dp[k][j-tmp] != inf) { dp[i][j] = min(dp[i][j],dp[k][j-tmp] + map[i][k]); } } } printf("%d\n",dp[1][bit-1]); } return 0; }