感覺自己學狀壓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;
}