Algorithm/DP

BOJ#9520 NP-Hard

밤이2209 2017. 4. 6. 21:42

BOJ#9520 NP-Hard


* 문제

https://www.acmicpc.net/problem/9520


* 풀이

- 규칙 : 번호가 K인 도시를 방문하려면, K보다 작은 번호를 가진 모든 도시를 K번을 방문하기 전에 모두 방문하거나, 방문한 후에 모두 방문해야 한다.

즉, K보다 번호가 작은 도시 중 하나를 K번 이전에 방문하고, 다른 하나를 K번 이후에 방문하면 안된다.


위 규칙을 만족하는 방문 수열은 아래와 같이 만들 수 있습니다.


맨 처음 1번 도시를 방문 : {1}

그 다음 2번 도시는 수열의 왼쪽 또는 오른쪽에 들어갈 수 있습니다 : {2, 1}, {1, 2}

그 다음 3번 도시는 수열의 왼쪽 또는 오른쪽에 들어갈 수 있습니다 : {3, 2, 1}, {2, 1, 3}, {3, 1, 2}, {1, 2, 3}

그 다음 4번 도시는 ...


즉, 각각의 도시는 왼쪽에 붙을지, 오른쪽에 붙을지 선택하면 됩니다. 그리고 선택의 기준은 N번 도시를 방문할 때까지의 cost가 작은 쪽으로 선택하면 됩니다.

그리고 각 도시를 수열에 붙이기 위해서는 수열의 왼쪽, 오른쪽 도시가 무엇인지 알고 있을 필요가 있습니다.


dp[left][right] : 양 끝이 left, right인 방문 수열에서 N번째 도시까지 방문했을 때, 최소 비용

solve(left, right) : dp[left][right]를 리턴하는 재귀 함수


int next = max(left, right) + 1;

dp[left][right] = min(next를 왼쪽에 붙이는 경우, next를 오른쪽에 붙이는 경우) = min(weight[next][left] + solve(next, right), weight[right][next] + solve(left, next)



* 나의 코드

https://github.com/stack07142/BOJ/blob/master/BOJ%239520_NP-Hard/src/Main.java


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

/**
* BOJ#9520 NP-Hard
* https://www.acmicpc.net/problem/9520
*/

public class Main {

static final int FRONT = 0;
static final int BACK = 1;
static final int MIN = 2;

static int N;
static int[][] weight = new int[1501][1501];
static int[][] dp = new int[1501][1501];

static {

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

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

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

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

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

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

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

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

System.out.println(solve(1, 1));

} // main

static int solve(int left, int right) {

if (dp[left][right] >= 0) return dp[left][right];

int next = Math.max(left, right) + 1;

if (next > N) return 0;

return dp[left][right] = Math.min((weight[next][left] + solve(next, right)), (weight[right][next] + solve(left, next)));
}
}



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

BOJ#5557 1학년  (0) 2017.04.08
BOJ#2098 외판원 순회  (0) 2017.04.07
BOJ#12101 1, 2, 3 더하기 2  (0) 2017.04.06
BOJ#11048 이동하기  (0) 2017.04.06
BOJ#11058 크리보드  (2) 2017.04.05