感觉自己学状压DP先做这题比较正确。。。
模型比较简单。
因为是可以多次经过同一个地方,所以先用floyd松弛出任意两点间最短距离。
然后枚举状态跑答案。
因为还要回到起点, 所以答案要加上mp[i][0]
#include <cstdio> #include <iostream> #include <cstring> #define inf 0x3f3f3f3f #define ms(x) memset(x, 0, sizeof(x)) #define ll long long using namespace std; const int N = 1<<15; const int mod = 1e9+7; int n, mp[12][12]; bool vis[12]; int dp[N][15]; int ans; int main() { while(scanf("%d", &n)!=EOF) { if(n==0) break; for(int i=0; i<=n; i++) { for(int j=0; j<=n; j++) { scanf("%d", &mp[i][j]); } } for(int k=0;k<=n;k++){ for(int i=0;i<=n;i++){ for(int j=0;j<=n;j++){ if(i==j) continue; if(mp[i][j]>mp[i][k]+mp[k][j]){ mp[i][j] = mp[i][k]+mp[k][j]; } } } } int m = (1<<n); for(int S = 0; S<m; S++){ for(int i=1;i<=n;i++){ if(S == (1<<(i-1))){ dp[S][i] = mp[0][i]; } else if(S & (1<<(i-1)) ){ dp[S][i] = inf; for(int j=1;j<=n;j++){ if(S & (1<<(j-1)) && j!=i){ dp[S][i] = min(dp[S][i], dp[S^(1<<(i-1))][j] + mp[j][i]); // 这个^用的就很灵性 } // 因为S的第(i-1)为1,所以异或后该位就变成了0 } } } } int ans = 1<<30; for(int i=1;i<=n;i++){ ans = min(ans, dp[m-1][i] + mp[i][0]); } printf("%d\n", ans); } return 0; }