import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;
public class Main {
static final int INF = (int) 1e9;
static int N;
static int[][] map, dp;
public static void main(String[] args) throws IOException {
init();
print();
}
private static void init() throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = null;
N = Integer.parseInt(br.readLine());
// 도시 연결 정보 입력
map = new int[N][N];
for (int i = 0; i < N; i++) {
st = new StringTokenizer(br.readLine());
for (int j = 0; j < N; j++) {
map[i][j] = Integer.parseInt(st.nextToken());
}
}
// 최단거리 테이블 초기화(-1 : 미방문)
dp = new int[N][1 << N];
for (int i =0; i < N ; i++) {
Arrays.fill(dp[i], -1);
}
}
private static void print() {
System.out.println(tsp(0, 1));
}
private static int tsp(int now, int visited) {
// 모든 도시를 방문한 경우
if (visited == ((1 << N) - 1)) {
if (map[now][0] == 0) return INF;
return map[now][0];
}
/* 아래와 같이 처리를 안해주면 58%에서 시간초과 발생 */
// 이미 방문한 경우 수행하지 않음
if (dp[now][visited] != -1) return dp[now][visited];
// 방문처리
dp[now][visited] = INF;
for (int i = 0; i < N; i++) {
// 이미 방문했으면 처리 X
if (map[now][i] == 0 || (visited & (1 << i)) != 0) continue;
// dp[i][j] : 현재 있는 도시가 i이고, 지금까지 방문한 도시들의 집합이 j 일 때
// 방문하지 않은 다른 도시들을 모두 방문한 뒤 돌아오는 최소 비용
// 현재 최솟값과 다음도시를 방문한 결과와의 최솟값 비교
dp[now][visited] = Math.min(dp[now][visited], tsp(i, visited | (1 << i)) + map[now][i]);
}
return dp[now][visited];
}
}
DP[현재 도시][방문한 도시] = 나머지 도시들을 방문하는데 드는 최소비용
dp
테이블의 값이 INF 인 경우로 해주어서 58% 쯤에서 계속해서 시간 초과가 발생하였음. 미방문 지점은 -1 처리를 해야함