感觉自己学状压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;
}