https://www.acmicpc.net/problem/12865
12865번: 평범한 배낭
첫 줄에 물품의 수 N(1 ≤ N ≤ 100)과 준서가 버틸 수 있는 무게 K(1 ≤ K ≤ 100,000)가 주어진다. 두 번째 줄부터 N개의 줄에 거쳐 각 물건의 무게 W(1 ≤ W ≤ 100,000)와 해당 물건의 가치 V(0 ≤ V ≤ 1,000)
www.acmicpc.net
평범한 배낭 문제에서 가치가 높은 물건부터 선택하면 최대 가치를 만들 수 있는가?
아닙니다. 아래의 예시를 보면, 무게가 1000인 물건을 먼저 넣으면 가치를 최대로 만들 수 없습니다.
7 1000 1000 10 500 1 100 9 100 8 90 8 80 6 70 4
평범한 배낭 문제는 다이나믹 프로그래밍을 이용하여 해결할 수 있습니다.
테이블 d[i]는 배낭에 넣을 수 있는 무게가 i일 때, 가치의 최댓값을 나타냅니다.
무게가 w[i]인 i번째 물건을 무게가 j(0 ≤ j ≤ k)인 배낭에 넣어보고, 무게가 j + w[i]인 배낭도 가치가 커지는 지 확인해보면 됩니다.
아래 테스트 케이스로 예를 들어보겠습니다.
4 7 6 13 4 8 3 6 5 12
아래는 d[i], temp[i]는 초기 상태입니다.
temp[i]는 d[i]의 변경사항을 일괄 적용시키기 위한 배열입니다.
물건 번호 | 무게 | 가치 |
1 | 6 | 13 |
0 (무게) | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
d[i] | 0 (가치) | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
temp[i] | 0 (가치) | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
현재, d[0], d[1]은 0입니다.
이 배낭에 첫번째 물건을 넣으면 temp[0 + 6] = max(0, 13) = 13, temp[1 + 6] = max(0, 13) = 13이 됩니다.
첫번째 물건을 넣을 수 있는 배낭을 모두 갱신 시켜주었으므로, temp를 d[i]에 기록해줍니다.
0 (무게) | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
d[i] | 0 (가치) | 0 | 0 | 0 | 0 | 0 | 13 | 13 |
temp[i] | 0 (가치) | 0 | 0 | 0 | 0 | 0 | 13 | 13 |
물건 번호 | 무게 | 가치 |
2 | 4 | 8 |
현재, d[0], d[1]은 0입니다.
이 배낭들에 두번째 물건을 넣으면 temp[0 + 4] = max(0, 8) = 8이 되고, temp[1 + 4] = max(0, 8) = 8이 됩니다.
현재, d[2], d[3]은 0입니다.
이 배낭들에 두번째 물건을 넣으면 temp[2 + 4] = max(13, 8) = 13, temp[3 + 4] = max(13, 8) = 13이 됩니다.
두번째 물건을 넣을 수 있는 배낭을 모두 갱신 시켜주었으므로, temp를 d[i]에 기록해줍니다.
0 (무게) | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
d[i] | 0 (가치) | 0 | 0 | 0 | 8 | 8 | 13 | 13 |
temp[i] | 0 (가치) | 0 | 0 | 0 | 8 | 8 | 13 | 13 |
이와 같은 방법으로 모든 물건에 대해 반복해주면 아래와 같은 테이블을 얻을 수 있습니다.
즉, 무게가 k일 때, 최대 가치 d[k] = 14를 얻을 수 있습니다.
0 (무게) | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
d[i] | 0 (가치) | 0 | 0 | 6 | 8 | 8 | 13 | 14 |
temp[i] | 0 (가치) | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
이차원 배열로 해결하는 방법보다 메모리를 더 적게 사용하여 풀 수 있습니다.
아래는 전체 코드입니다.
#include <bits/stdc++.h> using namespace std; int w[101], v[101]; int d[100010], temp[100010]; // d[i]는 무게가 i일 때, 배낭에 넣을 수 있는 가치의 최댓값 int n, k; int main(){ ios::sync_with_stdio(0); cin.tie(0); cin >> n >> k; // n, k 입력 받음 for(int i = 1 ; i <= n; i++) cin >> w[i] >> v[i]; // 무게와 가치 입력 받음 for(int i = 1; i <= n; i++){ // i는 물건의 번호를 나타냄 (1 ~ n) memcpy(temp, d, sizeof(temp)); for(int j = 0; j <= k; j++){ // j는 무게를 나타냄 // i번째 물건을 무게가 j(0 ≤ j ≤ k)인 배낭에 넣어보고, 무게가 j + w[i]인 배낭도 가치가 최대가 되는지 확인 if(j + w[i] <= k) // 무게가 j인 배낭에 무게가 w[i]인 물건을 넣어도 k보다 무게가 많이 나가지 않는 경우 temp[j + w[i]] = max(temp[j + w[i]], d[j] + v[i]); } for(int j = 0; j <= k; j++) d[j] = temp[j]; // d[i] 갱신 } cout << d[k]; }
아래는 문제 풀이에 사용된 테스트케이스입니다.
7 100 7 4 8 6 9 8 10 8 10 9 50 1 100 10 -> 36
'Algorithm > Dynamic Programming' 카테고리의 다른 글
[SW Expert Academy 1247번] 최적 경로 (0) | 2022.07.02 |
---|---|
[백준 4883번] 삼각 그래프 (C++) (0) | 2022.05.06 |
[백준 11057번] 오르막 수 (C++) (0) | 2022.05.05 |
[백준 9465번] 스티커 (C++) (0) | 2022.05.05 |
[백준 11052번] 카드 구매하기 (C++) (0) | 2022.05.05 |