Algorithm/DP

BOJ#2098 외판원 순회

밤이2209 2017. 4. 7. 16:40

BOJ#2098 외판원 순회


* 문제


* 풀이

dp 문제입니다.

(주의점, 힌트)
1. 사이클이므로 어느 점을 시작점으로 잡아도 상관없다.
2. 마을 방문 여부를 매개변수로 넘겨주기 위해서는 ? 비트마스크를 사용하자.
3. 시간 복잡도 : O(N^2 * 2^N)


* 나의 코드

https://github.com/stack07142/BOJ/blob/master/BOJ%232098_TSP/src/Main.java


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;

/**
* BOJ#2098 외판원 순회
* https://www.acmicpc.net/problem/2098
*/

public class Main {

static int N;
static int[][] W = new int[16][16];

static final int INF = 100000000;
static final int SOURCE = 0;
static final int NOT_CONNECTED = 0;
static final int NOT_VISITED = -1;

// dp[N][B] : 현재 N 마을에서 B에 속한 마을들을 방문했을 때, 나머지 마을들을 방문 후 시작점으로 돌아갈때 최소 cost
static int[][] dp = new int[16][1 << 16];

static {

for (int i = 0; i < 16; i++) {

Arrays.fill(dp[i], NOT_VISITED);
}
}

public static void main(String[] args) throws IOException {

// input
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

N = Integer.parseInt(br.readLine());

for (int i = 0; i < N; i++) {

StringTokenizer st = new StringTokenizer(br.readLine());
for (int j = 0; j < N; j++) {

W[i][j] = Integer.parseInt(st.nextToken());
}
}

// solve, 시작점 & 도착점 : 0
System.out.println(solve(SOURCE, 1 << SOURCE));
}

static int solve(int cur, int B) {

// memoization
if (dp[cur][B] != NOT_VISITED) return dp[cur][B];

// 기저 조건, 모든 마을을 방문하고 시작점(0)으로 되돌아가야 하는 경우
if (B == (1 << N) - 1) {

return dp[cur][B] = W[cur][SOURCE] != NOT_CONNECTED ? W[cur][SOURCE] : INF;
}

// 하위 문제
dp[cur][B] = INF;
for (int i = 0; i < N; i++) {

// 갈 수 없거나, 방문했던 마을이라면
if (W[cur][i] == NOT_CONNECTED || (B & (1 << i)) > 0) continue;

dp[cur][B] = Math.min(dp[cur][B], solve(i, B | (1 << i)) + W[cur][i]);
}

return dp[cur][B];
}
}


'Algorithm > DP' 카테고리의 다른 글

BOJ#2666 벽장문의 이동  (0) 2017.04.08
BOJ#5557 1학년  (0) 2017.04.08
BOJ#9520 NP-Hard  (0) 2017.04.06
BOJ#12101 1, 2, 3 더하기 2  (0) 2017.04.06
BOJ#11048 이동하기  (0) 2017.04.06