#include #include //小数点出力用 //cout << fixed << setprecision(10) << ans; #include #include #include #include #include #include #include #include using ll = long long; using namespace std; #define modPHash (ll)((1LL<<61)-1) #define modP (ll)998244353 bool chkrng0idx(int pos, int sup) { return (0 <= pos && pos < sup); } int clk4(int num) { return (num - 2) * (num % 2); } void yn(bool tf) { cout << (tf ? "Yes\n" : "No\n"); } int main() { cin.tie(nullptr); ios::sync_with_stdio(false); int N; cin >> N; //これは嘘解法 dp[S][i] = 訪問済み頂点の集合がSで現在地点iとなるようにできる最速時刻とする。 int dp[1 << 16][16] = { 0 }; int dpPre[1 << 16][16] = { 0 }; int D[16][16]; for (int i = 0;i < N;i++) { for (int j = 0;j < N;j++) { cin >> D[i][j]; } } for (int k = 1;k < (1 << N);k++) { for (int i = 0;i < N;i++) { dp[k][i] = 1e9; dpPre[k][i] = 1e9; } } dp[1][0] = 0; for (int k = 3;k < (1 << N);k += 2) { for (int i = 0;i < N;i++) { if ((k >> i) & 1) { for (int j = 0;j < N;j++) { if (i == j)continue; if ((k >> j) & 1) { if (dp[k][i] > dp[k - (1 << i)][j] + D[j][i]) { dp[k][i] = dp[k - (1 << i)][j] + D[j][i]; dpPre[k][i] = j; } } } } } } int ans = 1e9; int id = 1e9; for (int i = 1;i < N;i++) { if (ans > dp[(1 << N) - 1][i]) { ans = dp[(1 << N) - 1][i]; id = i; } } vectorV; int bit = 1 << N; bit--; while (id != 0) { V.push_back(id); int preid = dpPre[bit][id]; bit -= (1 << id); id = preid; } reverse(V.begin(), V.end()); { int nowT = 0; int nowP = 0; int Score = 0; vectorT(N); for (int i = 0;i < N - 1;i++) { nowT += D[nowP][V[i]]; nowP = V[i]; Score += nowT; } ans = Score; } cout << ans; }