#include <stdio.h> /** * 原題: * 一個賊在偷竊一家商店時發現了N件物品,其中第i件值v[i]元,重w[i]磅。 * 他希望偷走的東西總和越值錢越好,但是他的揹包只能放下W磅。 * 請求解如何放能偷走最大價值的物品,這裏v[i]、w[i]、W都是整數 */ #define MAX(x,y) (x>y?x:y) #define N 5 #define W 11 static int v[N] = {5,3,4,5,7}; static int w[N] = {2,3,4,6,8}; /** * 思路如下 * 設子問題爲:從第i件物品開始選擇,當前揹包剩餘可容量爲j,求出在此條件下所能獲得的最大價值max_v * 找出邊界:顯然i=N時,max_v=0(i=N時,說明已經沒有物品可選了), j=0時,max_v=0(可容量爲0,自然沒有物品可選,價值自然爲0) */ //解法1:遞歸 int solve_1(int i, int j){ if (j == 0 || i == N) return 0; //容量不夠時, 只能選擇嘗試下一件物品 if (w[i] > j) return solve_1(i+1, j); //容量足夠時, 在選擇當前物品和嘗試下一件物品之中選擇價值最高的 return MAX(solve_1(i+1,j-w[i]) + v[i], solve_1(i+1, j)); } //解法2:遞歸+記憶數組的dp static int memo[N+1][W+1]; int solve_2(int i, int j){ if (j == 0 || i == N) return memo[i][j] = 0; if (memo[i][j] > -1) return memo[i][j]; //容量不夠時, 只能選擇嘗試下一件物品 if (w[i] > j) return memo[i][j] = solve_2(i+1, j); //容量足夠時, 在選擇當前物品和嘗試下一件物品之中選擇價值最高的 return memo[i][j] = MAX(solve_2(i+1,j-w[i]) + v[i], solve_2(i+1, j)); } //解法3:遞推形 static int max_v[N+1][W+1]; int solve_3(){ for (int i = N-1; i >= 0; --i) { for (int j = 1; j <= W; ++j) { if (w[i] > j) max_v[i][j] = max_v[i+1][j]; else max_v[i][j] = MAX(max_v[i+1][j-w[i]]+v[i], max_v[i+1][j]); } } return max_v[0][W]; } int main() { printf("solve_1:%d\n", solve_1(0, W)); for (int i = 0; i <= N; ++i) { for (int j = 0; j <= W; ++j) { memo[i][j] = -1; } } printf("solve_2:%d\n", solve_2(0, W)); // for (int i = 0; i <= N; ++i) { // for (int j = 0; j <= W; ++j) { // printf("%d\t", memo[i][j]); // } // printf("\n"); // } printf("solve_3:%d\n", solve_3()); // for (int i = 0; i <= N; ++i) { // for (int j = 0; j <= W; ++j) { // printf("%d\t", max_v[i][j]); // } // printf("\n"); // } return 0; }
運行結果:
solve_1:13
solve_2:13
solve_3:13