중요하거나 어려웠던 문제에 대해 작성합니다.
- 2차원 DP
- Knapsack 문제
가장 기본적인 배낭 문제(Knapsack) 이여서 선정하였다. 문제의 경우 다음 링크를 클릭하면 된다.
배낭 문제는 크게 물건을 잘라서 넣을 수 있는 분할이 가능한 배낭 문제와 불가능한 문제(0-1 배낭 문제) 로 구분됩니다. 전자는 그리디 알고리즘으로 해결하고, 후자는 DP(Dynamic Programing) 이나 백트레킹으로 해결합니다.
해당하는 백준 문제 #12865는 물건들을 잘라서 넣을 수가 없습니다. 그래서 넣거나 안넣거나 둘만 가능하기에 0-1 배낭 문제에 속합니다.
위키피디아에 따라, 해당 문제의 pseudocode는 아래와 같습니다.
// 입력:
// 가치 (배열 v)
// 무게 (배열 w)
// 물건 수 (n)
// 최대 무게 (W)
array dp[0..n, 0..W];
for j from 0 to W do:
dp[0, j] := 0
for i from 1 to n do:
dp[i, 0] := 0
for i from 1 to n do:
for j from 1 to W do:
if w[i] > j then:
dp[i, j] := dp[i-1, j]
else:
dp[i, j] := max(dp[i-1, j], dp[i-1, j-w[i]] + v[i])
과정에 따라
i
의 역할은 담는 물건의 인덱스, 열 인덱스 j
의 역할은 담는 무게를 의미합니다. 그리고 dp[i, j]
는 가치가 들어갑니다.dp
에서 현재 물건 인덱스 i
와 무게 j
에서 최대 가치를 구하는 상황을 생각해보면 두가지 과정을 생각할 수 있습니다.
i
번째 물건 그냥 넘기기i
번째 물건 추가하기
- 물건을 그냥 넘기므로 무게가 변하지 않습니다. 무게는 현재 무게와 같은 값을 가져옵니다. 즉,
dp[i-1, j]
입니다.- 이번에는 사용합니다. 물건을 추가했을 때 물건을 포함한 무게인
j
가 목표이므로 가져올 값은i
번째 물건의 무게w[i]
를 뺀 것에서 가져와야 구할 수가 있습니다. 다만, 물건을 추가하기에 값에는 추가한 물건의 가치v[i]
를 더해야 됩니다. 즉,dp[i-1, j-w[i]] + v[i]
입니다.
j
는 1인데, w[i]
가 1억이라면..? 기준보다 무거운 물건에 대해서는 패스하도록 합니다. 즉, dp[i-1, j]
입니다.위와 같은 과정을 활용하여 문제를 해결하면 아래와 같습니다.
import sys
N, K = map(int,sys.stdin.readline().rstrip().split())
DP = [[0 for j in range(K + 1)] for i in range(N + 1)]
bag = [(0, 0)]
for _ in range(N):
W, V = map(int,sys.stdin.readline().rstrip().split())
bag.append((W, V))
for i in range(1, N+1):
w, v = bag[i]
for j in range(1, K+1):
if w > j:
DP[i][j] = DP[i-1][j]
else:
DP[i][j] = max(DP[i-1][j], DP[i-1][j-w]+v)
print(DP[N][K])
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) throws IOException{
StringTokenizer st;
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
st = new StringTokenizer(br.readLine());
int N = Integer.parseInt(st.nextToken());
int K = Integer.parseInt(st.nextToken());
int[][] dp = new int[N + 1][K + 1];
int[][] bag = new int[N + 1][2];
for(int i = 1; i <= N; i++) {
st = new StringTokenizer(br.readLine());
bag[i][0] = Integer.parseInt(st.nextToken());
bag[i][1] = Integer.parseInt(st.nextToken());
}
for(int i = 1; i <= N; i++) {
int w = bag[i][0];
int v = bag[i][1];
for(int j = 1; j <= K; j++) {
if(w > j) {
dp[i][j] = dp[i - 1][j];
} else {
dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - w] + v);
}
}
}
System.out.println(dp[N][K]);
br.close();
}
}