💻코딩테스트/백준

[백준/C++] 12865번 : 평범한 배낭 (DP 문제, 0-1 배낭 문제, 0-1 Knapsack)

공대 컴린이 2023. 7. 25. 13:59
728x90

평범한 배낭 

문제

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

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

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

4 7
6 13
4 8
3 6
5 12

예제 출력 1

14

해당 문제는 배낭문제라는 알고리즘의 유형 중 하나이다.

나는 배낭문제가 그냥 백준 문제 이름인 줄 알았는데 알고리즘 유형으로 존재하는거였다 ㅎㅎ..

 

문제에서 준서가 가방에 싸야하는 짐을 찢어서 넣을 수 없기 때문에 해당 문제는 배낭문제 중에서도 DP를 이용하여 풀이하는 "0-1 배낭문제" 이다.

 

dp는 [물건번호][무게] 를 나타내는 2차원 배열로 구성하였다.

물건 번호는 N의 개수만큼 순서대로 입력받는 물건들의 순서를 나타내며, 무게는 1부터 최대 무게인 W까지의 가방 최대무게를 저장한다.

 

0-1 배낭문제의 핵심 풀이는

"이전 물건을 담았을 때의 가중치"와, "현재 물건을 담고 남은 무게만큼은 이전 물건을 담았을때의 가중치"를 더하는 경우 중, 더 큰 가중치 값을 갖는 경우를 선택하여 dp[i][j]에 저장하는 것이다.

 

수식으로 나타내면 다음과 같다.

 

이전 물건을 담았을 때의 가중치 : dp[n-1][j]
현재 물건을 담고 남은 무게만큼 이전 물건을 담았을 때의 가중치 : dp[i-1][j - Weight[i]] + Value[i]

📌 예시 1

해당 개념을 2번째 물건(무게:4, 가치:8)이 무게 6을 만드는 최댓값의 경우로 예시를 들어 설명해보면 다음과 같다.

2번 물건이 무게 6을 만들기 위해 2번 이전 물건을 담았을 때의 가중치인 [2-1][6] = [1][6]을 비교하였다.

[1][6]의 값은 13의 가중치를 갖고 있다.

 

또한, 2번 물건을 담고 남은 무게만큼 이전 물건을 담았을 때의 가중치를 구하기 위해, 무게 6에서 2번 물건의 무게인 4를 빼어 6 - 4 = 2, 남은 무게를 이전 물건까지 담은 가중치 [2-1] = 1 로 비교하였다.

즉, [2-1][6-4] + 2번 물건의 가치 8 = [1][2] + 8 = 8 이 되는 것이다.

 

두 가중치를 각각 비교했을 때 2번 물건을 담는 경우보다, 2번 물건을 담지 않고 이전 물건인 1번 물건만 담은 경우가 13의 가중치로 더 큰 값을 가지므로, [2][6] 의 가중치는 13이 된다.

📌 예시 2

두번째 예시를 보자.

 

3번 물건이 무게 7을 만들기 위해 가질 수 있는 경우의 수는

1. 3번 물건을 담지 않고 이전 물건인 2번 물건까지만 담은 가중치 값: [2][7] = 13

2. 3번 물건을 담고, 남은 무게만큼 이전 물건을 담은 가중치 값: (7 - 3번물건의 무게 5) = 4

이전 물건 중 무게 4의 가중치 값 [3-1][4] = [2][4] = 8

3번 물건을 담았으니 3번 물건의 가중치 값 더해주기 => 8 + 6 = 14

 

두 경우를 비교했을 때 3번 물건을 담는 경우가 더 큰 가중치 14를 가지므로, [물건3][무게7]의 가중치는 14가 된다.


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

using namespace std;

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

	int N, K;
	cin >> N >> K;
	vector<pair<int, int>> Objects(N+1); // 무게, 가치
	for (int i = 1; i <= N; i++)
		cin >> Objects[i].first >> Objects[i].second;

	vector<vector<int>> dp(N + 1, vector<int>(K + 1));
	for(int i = 1; i <= N; i++)
	{
		for(int j = 1; j <= K; j++)
		{
			if (j >= Objects[i].first)
				dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - Objects[i].first] + Objects[i].second);
			else
				dp[i][j] = dp[i - 1][j];
		}
	}

	cout << dp[N][K];
	return 0;
}

 

이러한 원리 그대로 소스코드를 작성해보면 위와 같다.

 

무게와 가치를 입력받을 2차원 vector를 선언해주고, [N+1][K+1]의 크기를 갖는 2차원 벡터 dp를 선언해주었다.

이후, 1번 물건부터 N번 물건까지 for문을 수행하며, 무게 1부터 무게 K까지의 2중 for문을 수행하였다.

 

실시간 무게 j가 물건 i 의 무게보다 큰 경우에만, 물건 i 를 담는 경우와 안담는 경우 중 큰 값을 비교할 수 있다.

실시간 무게 j 가 물건 i 의 무게를 넘지 못한다면, 배낭이 넘치므로 물건 i를 담을 수 없고 이전 물건을 담은 가중치값을 그대로 이전해야 한다.

 

최종적으로는 모든 물건을 다 넣은 마지막 물건 번호인 [N] 과, 최대 무게인 [K]의 원소를 가지고 dp[N][K]를 출력해주었다.


🐸 일주일 뒤 한번 더 풀어본 소스코드

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

using namespace std;

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

	int N, K;
	cin >> N >> K;

	vector<int> Weights(N+1);
	vector<int> Values(N+1);
	for(int i = 1; i <= N; i++)
		cin >> Weights[i] >> Values[i];

	vector<vector<int>> dp(N + 1, vector<int>(K + 1));
	for(int i = 1; i <= N; i++)
	{
		for (int j = 1; j <= K; j++)
		{
			if (j >= Weights[i]) // ★ 빼먹지말자!!!!!
				dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - Weights[i]] + Values[i]);
			else
				dp[i][j] = dp[i - 1][j];
		}
	}

	cout << dp[N][K];

	return 0;
}

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

https://namu.wiki/w/%EB%B0%B0%EB%82%AD%20%EB%AC%B8%EC%A0%9C

 

배낭 문제 - 나무위키

무게 대비 가치가 다른 물건들을 일정한 용량의 용기에 담아야 한다는 기본 틀에서, 바리에이션이 많다. 가방이 여러 개인 문제, 고려할 변수가 무게와 가치 외에도 더 있는 3개 이상의 변수 문

namu.wiki

 

728x90