#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