模型:求n个城市的最短hamilton回路,n<=15。
分析:看到n<=15这样的条件容易想到状态压缩DP。hamilton回路其实就是n个城市的一个圆排列,任选一个起点最后的结果都一样,我们不妨设结点0为起点,状态设计也就不难了。
状态设计:d[s][last],表示从结点0出发,已经走过的结点构成状态s,最后走的结点为last;
状态转移:d[s][last]=MIN(d[ns][k]+g[k][last]),ns为s中去掉last那一位,k为ns中是1的位(不能是起点0);
边界:当s中只有2位是1的时候,说明从0结点出发,到达last,所以直接返回g[0][last]。
结果:ans=MIN(d[(1<<n)-1][k]+g[0][k]),k=1,2……n-1
说明:这题坑爹的是NoAnswer的情况,题目没说明白,其实邻接矩阵中的0代表INF,说明不连通,就因为这个原因WA到吐血,最后问A了的人才明白。
View Code
#include <stdio.h> #include <string.h> #define N 16 #define INF 0x3f3f3f3f #define MIN(a,b) ((a)<(b)?(a):(b)) int n; int g[N][N]; int dp[1<<N][N]; int DP(int s,int last) { if(dp[s][last]!=-1) return dp[s][last]; int ns=s^(1<<last); if(ns==1) return dp[s][last]=g[0][last]; int ret=INF; for(int i=1;i<n;i++) { if((ns^(1<<i))<ns) ret=MIN(ret,DP(ns,i)+g[i][last]); } return dp[s][last]=ret; } int main() { int i,j; while(~scanf("%d",&n)) { for(i=0;i<n;i++) { for(j=0;j<n;j++) { scanf("%d",&g[i][j]); if(g[i][j]==0 && i^j) g[i][j]=INF; } } int ans=INF; memset(dp,0xff,sizeof(dp)); for(i=n-1;i;i--) { ans=MIN(ans,DP((1<<n)-1,i)+g[0][i]); } if(n==1) ans=0; if(n==2) ans=2*g[0][1]; if(ans<INF) printf("%d\n",ans); else puts("NoAnswer"); } return 0; }