[BOJ] 12865 평범한 배낭 (Python3)
문제
이 문제는 아주 평범한 배낭에 관한 문제이다.
한 달 후면 국가의 부름을 받게 되는 준서는 여행을 가려고 한다. 세상과의 단절을 슬퍼하며 최대한 즐기기 위한 여행이기 때문에, 가지고 다닐 배낭 또한 최대한 가치 있게 싸려고 한다.
준서가 여행에 필요하다고 생각하는 N개의 물건이 있다. 각 물건은 무게 W와 가치 V를 가지는데, 해당 물건을 배낭에 넣어서 가면 준서가 V만큼 즐길 수 있다. 아직 행군을 해본 적이 없는 준서는 최대 K만큼의 무게만을 넣을 수 있는 배낭만 들고 다닐 수 있다. 준서가 최대한 즐거운 여행을 하기 위해 배낭에 넣을 수 있는 물건들의 가치의 최댓값을 알려주자.
입력
첫 줄에 물품의 수 N(1 ≤ N ≤ 100)과 준서가 버틸 수 있는 무게 K(1 ≤ K ≤ 100,000)가 주어진다. 두 번째 줄부터 N개의 줄에 거쳐 각 물건의 무게 W(1 ≤ W ≤ 100,000)와 해당 물건의 가치 V(0 ≤ V ≤ 1,000)가 주어진다.
입력으로 주어지는 모든 수는 정수이다.
출력
한 줄에 배낭에 넣을 수 있는 물건들의 가치합의 최댓값을 출력한다.
1
2
3
4
5
6
7
8
9
예제 입력 1
4 7
6 13
4 8
3 6
5 12
예제 출력 1
14
문제 풀이
아무리 생각해도 안풀려서 풀이를 보고 풀었다. 이 문제는 DP중에서도 냅색(Knapsack) 알고리즘으로 풀어야 한다고 한다. DP는 참… 풀어도 풀어도 적응이 안된다.
냅색 알고리즘은
- 분할 가능 배낭문제 (담을 수 있는 물건을 나눌 수 있을때 ex) 설탕, 소금…)
- 0-1 배낭 문제 (담을 수 있는 물건이 나누어 질 수 없을때 ex) 담는다 or 안담는다)
분할하여 설명하면 다음과 같다.
1) x축에는 가방 1~K 까지의 무게, y축은 물건 N개 개수 만큼의 배열을 만들어준다.
2) 행을 차례대로 돌며 다음과 같은 알고리즘을 수행한다.
3-0) 현재 물건이 현재 돌고있는 무게보다 작다면 바로 [이전물건]같은무게를 입력해준다.
3-1) 현재 물건을 넣어준다. 물건을 넣은 뒤의 남은 무게를 채울 수 있는 최댓값(knapsack[i-1][j-weight])을 위의 행에서 가져와 더해준다.
3-2) 현재 물건을 넣어주는 것보다. 다른 물건들로 채우는 값(knapsack[i-1][j])을 가져온다.
4) 3-1과 3-2 중 더 큰 값을 knapsack[i][j]에 저장해준다. 이 값은 현재까지의 물건들로 구성할 수 있는 가장 가치 높은 구성이다.
5) knapsack[N][K]는 곧, K무게일 때의 최댓값을 가리킨다.
따라서 Knapsack[i][j]를 돌며 해당 i(물건)에 따른 j(무게)의 최댓값을 구하는 것인데, 무게인 j가 해당 물건의 무게보다 작은 경우는 가방에 넣지 못하므로, 앞의 물건의 최대값을 그대로 갖고, 무게 j가 물건의 weight와 같거나 크다면 해당 물건을 넣을수 있는 공간이 생겼다는 것이므로 그 물건이 없던값, [i][j-weight] 와 해당 물건이 들어가지 않은 값 [i-1][j]를 비교하여 더 큰값을 넣어주는 것을 반복하면 된다.
코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
N, K = map(int, input().split())
feature = [[0,0]]
for i in range(N):
W,V = map(int, input().split())
feature.append([W,V])
Knapsack = [[0 for i in range(K+1)] for i in range(N+1)]
for i in range(1,N+1):
for j in range(1,K+1):
weight = feature[i][0]
value = feature[i][1]
if j < weight:
Knapsack[i][j] = Knapsack[i-1][j]
else:
Knapsack[i][j] = max(value + Knapsack[i-1][j-weight], Knapsack[i-1][j])
print(Knapsack[-1][-1])
1
2
3
4
5
6
4 7
6 13
4 8
3 6
5 12
14
1
print(knapsack[N][K])
1
14
댓글남기기