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
1. DFS
입력 값 N, K에 대하여,
N은 물품의 수이고, K는 준서가 버틸 수 있는 무게이다.
K 무게를 넣을 수 있고,
입력받은 물건을 차례로 인덱스를 부여할 때, 해당 인덱스부터 탐색하여 가능한 경우를 찾는다.
가능한 경우는 1) 물건을 넣지 않는 경우, 2) 물건을 넣는 경우가 있고,
1) 의 값과 2) + 물건의 가치 값 중 큰 값을 반환한다.
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int dfs(int weight, int idx, vector<pair<int, int> >& tmp, int n){
int i, first, value;
//탐색할 물건이 없는 경우
//더이상 물건을 넣지 않는 경우
if (idx == n || weight == 0)
return 0;
value = 0;
//물건을 넣는 경우
if (tmp[idx].first <= weight){
first = dfs(weight - tmp[idx].first, idx + 1, tmp, n) + tmp[idx].second;
value = max(first, value);
}
//물건을 넣지 않는 경우
value = max(value, dfs(weight, idx + 1, tmp, n));
//최대값 반환
return value;
}
int main(){
int n, k;
int w, v;
vector<pair<int, int> > backpack;
cin >> n >> k;
for (int i = 0; i < n; i++){
cin >> w >> v;
backpack.push_back(pair<int, int>(w, v));
}
cout << dfs(k, 0, backpack, n) << endl;
return 0;
}
최악의 경우, 탐색할 인덱스가 0 ~ n 까지 모두 탐색하는 것으로 포화이진트리의 노드 개수는 트리의 깊이가 a 일 때, 2^n - 1 개이다.
따라서, O(2^n)의 시간이 소요된다.
n = 100일 때, 최악의 경우, 2^100번 시행되므로 시간 초과가 발생한다.
2. DP
위와 같은 방식으로 작성하되, 시간 초과를 막기위해 값들을 한 번 계산한 뒤 결과를 저장한다.
이때, 인덱스가 클수록, 배낭에 넣을 수 있는 무게가 작을 수록, 다른 값을 덜 참조하므로 순서에 따라 계산을 한다!
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int dp(int weight, int idx, vector<pair<int, int> >& tmp, int n, vector<vector<int> >& result){
int i, first, value;
value = 0;
//배낭에 넣는 경우
if (tmp[idx].first <= weight)
value = result[weight - tmp[idx].first][idx + 1] + tmp[idx].second;
//배낭에 넣지 않는 경우
value = max(value, result[weight][idx + 1]);
//최대값 반환
return value;
}
int main(){
int n, k;
int w, v;
vector<pair<int, int> > backpack;
vector<vector<int> > result;
cin >> n >> k;
for (int i = 0; i < n; i++){
cin >> w >> v;
backpack.push_back(pair<int, int>(w, v));
}
//값 초기화
result.assign(k + 1, vector<int>(n + 1, -1));
//k == 0 인 경우
for (int i = 0; i <= n; i++)
result[0][i] = 0;
//i == n 인 경우
for (int i = 0; i <= k; i++)
result[i][n] = 0;
//result 값 구하기
for (int j = n - 1; j >= 0; j--){
for (int i = 1; i <= k; i++)
result[i][j] = dp(i, j, backpack, n, result);
}
//결과 출력
cout << result[k][0] << endl;
return 0;
}
소요 시간은 N * K + 2N + K 이므로, O(N * K)이고,
최대 10^2 * 10^5, 약 10^7 번 계산한다.
'Algorithm' 카테고리의 다른 글
[Programmers] 지형 이동 (0) | 2022.05.08 |
---|---|
[Programmers] 멀쩡한 사각형 (0) | 2022.05.07 |
[백준] 18111 마인크래프트 (0) | 2022.01.30 |