공부/백준

백준 12865번: 평범한 배낭(C++)

상연 2021. 2. 1. 23:01

목차

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

코드

#include <iostream>
using namespace std;

int n, k; // 물품의 개수, 준서가 버틸 수 있는 무게
int product[101][2]; // 물건의 무게와 가치 배열
int dp[101][100001];

int max(int a, int b){
	return a >= b ? a : b;
}

void solve(){
	int max_value = 0;
	for(int i=1; i<=n; i++){
		for(int j=1; j<=k; j++){
			dp[i][j] = dp[i-1][j];
			if(product[i-1][0] <= j){
				dp[i][j] = max(dp[i][j], product[i-1][1] + dp[i-1][j - product[i-1][0]]);
			}
			max_value = max(max_value, dp[i][j]);
		}
	}
	cout << max_value;
}



int main() {
	cin >> n >> k;
	for(int i=0; i<n; i++){
		cin >> product[i][0] >> product[i][1];
	}
	solve();
}

 

풀이

대표적인 DP문제입니다.

무게 1~K 까지 각각의 무게에서 준서가 들 수 있는 물건 중 최고의 가치를 찾으면 됩니다.

개인적으로 DP문제 풀이를 볼 때 메모이제이션 표가 있으면 이해하는게 편하다 생각하기에 표로 설명드립니다.

문제 예시 입출력을 기반으로 만들어진 표 입니다.

첫번째 행을 보시면 0~7까지의 수가 있습니다.

각각의 값은 들 수 있는 무게입니다.

 

첫번째 열을 보시면 입력받은 물건의 무게와 가치가 있습니다.

 

우선... 처음에는 아무 물건도 안 넣었다고 생각을 해 보겠습니다. 

당연히 들 수 있는 무게가 얼마가 되던 가치는 0이 됩니다.

 

다음으로 첫번째 물건 - 무게가 6이고 가치가 13인 물건을 가방에 넣어볼까요?

무게가 0~5 까지는 물건을 넣을 수도 없기 때문에 동일한 무게에 이전(물건이 없는 경우)물건의 가치를 가져옵니다.

dp[ i ][ j ] = dp[ i-1 ][ j ]

위의 표를 dp라는 2차원 배열이라 가정할 시에는 위와 같은 코드가 되겠습니다.

0을 가져오게 되겠죠.

 

무게가 6이 되는 순간부터는 첫번째 물건을 넣을수가 있게 됩니다. (조건문으로 생각해보기)

 

하지만, 넣을 수 있다고 그냥 넣어버리면 안됩니다.

최대값을 찾아야 겠죠?

최대값은 어떻게 알 수 있을까요?

이 물건을 담았을때 더 들 수있는 무게를 찾고, 그 무게에서 가장 큰 가치를 갖는 경우를 합해주면 됩니다.

빨간색 원으로 한 곳을 생각해보면

현재 들 수 있는 무게는 6 이며

담는 물건의 무게는 6입니다. 따라서 이전 행에서 ... 들수 있는 무게 (6) - 담는 물건의 무게(6) = 0

들 수 있는 무게가 0일때의 가치를 합해줬을 때 그 값이 이전 행의 값보다 큰 경우 교체해 줍니다.

점화식으로 보면

if(product[i-1][0] <= j)

dp[i][j] = max(dp[i][j], product[i-1][1] + dp[i-1][j - product[i-1][0]]);

이와 같이 되겠네요.

 

이러한 점을 잘 생각해서 위와같은 메모이제이션 표를 만든다고 생각하며 풀면 풀 수 있는 문제입니다.