문제링크: 여행 짐 싸기
유명한 문제인데 풀 때마다 새롭다.
이런 류의 문제들은 패턴이 있으니 기억하자.
배낭에 넣었을 때와 안넣을때의 값 중에 max를 취한다.
일단 최대 절박도를 구하는 함수를 구하고, 그 함수를 이용하여 선택한 item들을 재구성한다.
- recursive
무게가 capacity만큼 남았을 때, 해당 item부터 마지막 item들까지 넣었을 때 얻을 수 있는 최대절박도를 구하는 함수를 만든다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | #include <iostream> #define max(a,b) (a)>(b)?(a):(b) using namespace std; int C, N, W; typedef struct { char name[21]; int volumn; int needs; }Package; const int MAXW = 1001; const int MAXN = 101; Package goods[MAXN]; int cache[MAXW][MAXN]; int Pick[MAXN]; int Top = 0; // 최대 절박도를 return int pack(int capacity, int item) { if (item == N) return 0; int &ret = cache[capacity][item]; if (ret != -1) return ret; ret = 0; // 현재 item을 선택x ret = pack(capacity, item + 1); // 현재 item을 선택했을 때 절박도를 비교하여 max값을 취함. if(capacity>=goods[item].volumn) ret = max(ret, pack(capacity-goods[item].volumn, item+1)+goods[item].needs); return ret; } // 담긴 물품 void reconstruct(int capacity, int item) { if (item == N) return; // item번째 절박도와 item+1번째 절박도가 같으면.. 즉, item을 안담은 것임 if (pack(capacity, item) == pack(capacity, item + 1)) reconstruct(capacity, item+1); else { Pick[Top++] = item; reconstruct(capacity-goods[item].volumn, item + 1); } } void printItems() { cout << Top << endl; for (int i = 0; i < Top; i++) { cout << goods[Pick[i]].name << endl; } } void init() { for (int i = 0; i < MAXW; i++) for (int j = 0; j < MAXN; j++) cache[i][j] = -1; Top = 0; } int main() { freopen("input.txt", "r", stdin); cin >> C; for (int c = 0; c < C; c++) { cin >> N >> W; for (int i = 0; i < N; i++) { cin >> goods[i].name >> goods[i].volumn >> goods[i].needs; } init(); cout << pack(W, 0) << " "; reconstruct(W, 0); printItems(); } return 0; } | cs |
- iterative
pack 함수와 동일하게 2차원 배열을 이용하여 다시 구현해 보았다.
iterative하게 생각하는 것은 쉽지 않다. ㅠ.ㅠ
pack[item][weight]
이전 item들을 선택했을 때의 절박도를 저장해두고,
weight을 증가시키면서 item의 weight보다 커졌을 때, 이 전 item들을 선택했을 때의 절박도에 현재 절박도를 비교해
max 값을 갱신하면서 전체 item과 무게를 모두 for loop으로 돌며 계산한다.
item 추적
- N,W번째 절박도에서 전단계 item 선택으로 가면서 절박도가 달라질 때, 해당 item이 선택된 것이다.
- 무게를 빼준 후 다시 비교한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | #include <iostream> #define max(a,b) (a)>(b)?(a):(b) using namespace std; int C, N, W; typedef struct { char name[21]; int volumn; int needs; }Package; const int MAXW = 1001; const int MAXN = 101; Package goods[MAXN]; int Pick[MAXN]; int Top = 0; int Needs[MAXN][MAXW]; void pack2() { Needs[0][0] = 0; int maxV = 0; for (int item = 1; item <= N; item++) { for (int weight = 1; weight <= W; weight++) { // 현재 item을 넣지 않은 상태 maxV = Needs[item - 1][weight]; // 전단계 절박도에 현재 절박도를 더한 값이 전단계 절박도보다 크면 max값 갱신 if (weight >= goods[item].volumn && maxV < (Needs[item - 1][weight - goods[item].volumn] + goods[item].needs)) { maxV = Needs[item - 1][weight - goods[item].volumn] + goods[item].needs; } Needs[item][weight] = maxV; } } } void printItems() { int weight = W; int items[MAXN], index = 0; // 역으로 추적한다. for (int i = N; i > 0; i--) { // 이전 선택과 현재 선택의 절박도가 다를 때까지 item 건너뜀 if (Needs[i-1][weight] == Needs[i][weight]) continue; items[index++] = i; // 선택된 item 저장 weight = weight - goods[i].volumn; } cout << index << endl; for(int i=0;i<index;i++) cout << goods[items[i]].name << " "; cout << endl; } int main() { freopen("input.txt", "r", stdin); cin >> C; for (int c = 0; c < C; c++) { cin >> N >> W; for (int i = 1; i <= N; i++) { cin >> goods[i].name >> goods[i].volumn >> goods[i].needs; } pack2(); cout << Needs[N][W] << " "; printItems(); } return 0; } | cs |