题目
有N件物品和一个容量为V的背包。第i件物品的重量是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。
思路
首先假设物品数 N = 6,容量 V = 10。
容量数组 c 为:
c[0] | c[1] | c[2] | c[3] | c[4] | c[5] |
4 | 3 | 2 | 3 | 2 | 4 |
价值数组 w 为:
w[0] | w[1] | w[2] | w[3] | w[4] | w[5] |
12 | 9 | 14 | 6 | 8 | 13 |
每种物品可以选择放或者不放。对于 “ 将前 i 件物品放入容量为 v 的背包中”这个子问题,若只考虑第 i 件物品的策略(放或不放),那么就可以转化为一个只牵扯前 i-1 件物品的问题。如果不放第i件物品,那么问题就转化为“前i-1件物品放入容量为v的背包中”,价值为f[i-1][v];如果放第i件物品,那么问题就转化为“前i-1件物品放入剩下的容量为v-c[i]的背包中”,此时能获得的最大价值就是f [i-1][v-c[i]] 再加上通过放入第i件物品获得的价值w[i]。 用子问题定义状态: 即 f[i][v] 表示前 i 件物品恰放入一个容量为 v 的背包可以获得的最大价值。则其状态转移方程便是:f[i][v] = max{ f[i-1][v] , f[i-1][v-c[i]]+w[i] }。
以下模拟二维数组 f[i][v] 状态:
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | |
0 | 0 | 0 | 0 | 12 | 12 | 12 | 12 | 12 | 12 | 12 |
1 | 0 | 0 | 9 | 12 | 12 | 12 | 21 | 21 | 21 | 21 |
2 | 0 | 14 | 14 | 14 | 23 | 26 | 26 | 26 | 35 | 35 |
3 | 0 | 14 | 14 | 14 | 23 | 26 | 26 | 29 | 35 | 35 |
4 | 0 | 14 | 14 | 22 | 23 | 26 | 31 | 34 | 35 | 37 |
5 | 0 | 14 | 14 | 22 | 23 | 27 | 31 | 35 | 36 | 39 |
代码
#include#define N 6#define V 10int c[6] = { 4,3,2,3,2,4};int w[6] = { 12,9,14,6,8,13};void knapsack(){ int f[11]; int i,j,tmp; for(i = 0; i < V + 1 ; i++) f[i] = 0; for(i = 0; i < N; i++) { for(j = V+1; j >= c[i];j--) { tmp = f[j - c[i]] + w[i]; if(tmp > f[j]) f[j] = tmp; } } for(i = 0;i <= V; i++) printf("%d\t",f[i]);}int main(){ knapsack(); return 0;}