본문 바로가기
📊알고리즘/BOJ

[👊DP뿌시기 #11] (BOJ 12865) 평범한 배낭

by meteorfish 2023. 8. 23.
728x90

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

문제

이 문제는 아주 평범한 배낭에 관한 문제이다.

한 달 후면 국가의 부름을 받게 되는 준서는 여행을 가려고 한다. 세상과의 단절을 슬퍼하며 최대한 즐기기 위한 여행이기 때문에, 가지고 다닐 배낭 또한 최대한 가치 있게 싸려고 한다.

준서가 여행에 필요하다고 생각하는 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)가 주어진다.

입력으로 주어지는 모든 수는 정수이다.

출력

한 줄에 배낭에 넣을 수 있는 물건들의 가치합의 최댓값을 출력한다.

 


시도

처음에 어떤식으로 DP 테이블을 잡아야할지 고민되었다.

무게, 가치, 갯수 총 세개의 변수를 관리해야한다고 생각했다.

 

그래서 DP[i][j]를 i개일때의 j로 잡고 해서 이상한 값이 나왔다.

 

실수한 이유는 i를 개수로 잡게되면, 중복되는 값들이 많이 생기기 때문이다.

 

접근법

따라서, 이번에 경우를 생각해봤다.

예를 들어 2번째 아이템은 어떤 경우를 가질까?

 

1. 2번째 아이템이 포함되는 경우

2. 2번째 아이템이 포함되지 않는 경우

 

따라서, DP[i][j]를 i개가 아닌 i번째 아이템의 순서이면서, 무게가 j만큼일때의 최고 가치라고 정의하는 것이 옳다고 생각했다.

 

아이템이 총 3가지가 있다고 가정했을때,

DP[2][J]는 어떻게 될까? 위 경우를 나눠서 살피면

 

1. 2번째 아이템이 포함되는 경우 = DP[1][j - 2번아이템 무게] + 2번아이템 가치

2. 2번째 아이템이 포함되지 않는 경우 = DP[1][j]

 

단, 최대 들 수 있는 무게가 제한되어 있어 이는 유의해야한다.

 

이를 그림으로 표현하면 다음과 같다.

점화식도 살펴보면

그리고 무게 j는 아이템들의 무게에 의해 정해지기에, j의 값을 따로 잡으려고 했다.

그러나 어차피 무게의 리미트 값이 정해져있기 때문에, 이를 따로 잡을 필요 없이

for문을 돌면서 수행하면 된다.

코드

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>

using namespace std;

int dp[101][100001];
vector<pair<int, int>> items;

int main() {
	ios_base::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);

	int n, k, w, v;
	cin >> n >> k;
	items.push_back({ 0,0 });
	for (int i = 0; i < n; i++) {
		cin >> w >> v;
		items.push_back({ w,v });
	}

	// j를 굳이 딱 정확하게 할필요가 없음
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= k; j++) {
			if (j - items[i].first >= 0) {
				int no = dp[i - 1][j];
				int yes = dp[i - 1][j - items[i].first] + items[i].second;
				if (yes > no) {
					dp[i][j] = yes;
				}
				else {
					dp[i][j] = no;
				}
				//cout << j << endl;
			}

			else
				dp[i][j] = dp[i - 1][j];
		}
	
	}
	cout << dp[n][k];
}
728x90