#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int M = 1<<12;
typedef long long LL;
int dp[M][12];
int a[12][12];
//S是一个点的集合,dp[S][i]代表当遍历S这些点且最后通过i回到原点的最小路径
int main(){
//freopen("in", "r", stdin);
int n, m;
while(cin >> n && n){
for(int i = 0; i <= n; i++)
for(int j = 0; j <= n; j++)
scanf("%d", &a[i][j]);
for(int k = 0; k <= n; k++)
for(int i = 0; i <= n; i++)
for(int j = 0; j <= n; j++)
a[i][j] = min(a[i][j], a[i][k] + a[k][j]);
//先用弗洛伊德处理出任意两点的最短路径
m = (1 << n);
for(int S = 0; S < m; S++)
for(int i = 1; i <= n; i++)
if(S & (1 << (i-1))){//S集合是否包含i
if(S == (1 << (i-1))) dp[S][i] = a[0][i];//S集合只有i
else{
dp[S][i] = (1 << 30);//无穷大
for(int j = 1; j <= n; j++){
if(S & (1 << (j-1)) && i != j){//枚举所有的j,找出dp[S][i]的最小值
dp[S][i] = min(dp[S][i], dp[S^(1<<(i-1))][j] + a[j][i]);//S^(1 << (i-1))从S中拿出i
}
}
}
}
int ans = 1<<30;
for(int j = 1; j <= n; j++)//讨论每一个点作为最后一个点的结果
ans = min(ans, dp[m-1][j] + a[j][0]);
cout << ans << endl;
}
return 0;
}
08-05