背包九讲:
http://leafduo.com/oi/dd-pack/
分别运用递归,空间O(n*v)的递推和空间O(v)的递推解决01背包.
bag:运用递归,状态为bag(int n, int v),即 前n件物品恰放入一个容量为v的背包可以获得的最大价值。写出状态转移方程: bag(n, v)=max(bag(n-1, v-cost[n])+weight[n], bag(n-1, v))。终止条件为1. 背包容量小于零时(v<0)返回无穷小,因为是不可能发生的;2. 递归到第一个物品且此时背包容量小于第一个物品的重量(n==1 && v<cost[1]),返回零;3. 递归到第一个物品且此时背包容量大于等于第一个物品的重量(n==1 && v>=cost[1]),返回第一个物品的价值(weight)。
bag2运用空间度O(n*v)的递推。首先初始化,将数组f[][]成员全部置零。然后自底向上递推, 推f[n][v]时需要知道f[n-1][v-cost[n]]和f[n-1][v]两个值。其中需要考虑v-cost[n]小于零的情况:v-cost[n]小于零时f[n][v]=f[n-1][v](因为bag(n, 负数)==负无穷大)。
bag3将bag2的空间优化到O(v)。即只需要一维数组f2[]。所以每次递推n时需要覆盖原来f2中的数据。 f2[v]=max(f2[v-cost[n]]+weight[n], f2[v])。因为f2[v]需要知道f2[v-cost[n]的值,所以递推v时必须从后往前(即v=V....0)。此时可以对v的取值范围进行一次优化:当v-cost[n]小于零时,f2[v]=f2[v],值保持不变,所以可以缩小v的范围至v=V....cost[n]。
仔细考虑,还可以对v的范围优化,从最后一个物体向前考虑,因为只要得到最后f2[v]的答案,而f2[v]的答案来自于前一个物品f2[v]与f2[x]+weight[n]的最大值,所以前一个物品只需从后向前计算到f2[v-weight[n]]即可停止。以此类推第j个物品需要计算到f2[v-sum(weight[j]....weight[n])。此时又需要同cost取max,相见代码:)
再次经过优化的bag3:
分别运用递归,空间O(n*v)的递推和空间O(v)的递推解决01背包.
bag:运用递归,状态为bag(int n, int v),即 前n件物品恰放入一个容量为v的背包可以获得的最大价值。写出状态转移方程: bag(n, v)=max(bag(n-1, v-cost[n])+weight[n], bag(n-1, v))。终止条件为1. 背包容量小于零时(v<0)返回无穷小,因为是不可能发生的;2. 递归到第一个物品且此时背包容量小于第一个物品的重量(n==1 && v<cost[1]),返回零;3. 递归到第一个物品且此时背包容量大于等于第一个物品的重量(n==1 && v>=cost[1]),返回第一个物品的价值(weight)。
bag2运用空间度O(n*v)的递推。首先初始化,将数组f[][]成员全部置零。然后自底向上递推, 推f[n][v]时需要知道f[n-1][v-cost[n]]和f[n-1][v]两个值。其中需要考虑v-cost[n]小于零的情况:v-cost[n]小于零时f[n][v]=f[n-1][v](因为bag(n, 负数)==负无穷大)。
bag3将bag2的空间优化到O(v)。即只需要一维数组f2[]。所以每次递推n时需要覆盖原来f2中的数据。 f2[v]=max(f2[v-cost[n]]+weight[n], f2[v])。因为f2[v]需要知道f2[v-cost[n]的值,所以递推v时必须从后往前(即v=V....0)。此时可以对v的取值范围进行一次优化:当v-cost[n]小于零时,f2[v]=f2[v],值保持不变,所以可以缩小v的范围至v=V....cost[n]。
仔细考虑,还可以对v的范围优化,从最后一个物体向前考虑,因为只要得到最后f2[v]的答案,而f2[v]的答案来自于前一个物品f2[v]与f2[x]+weight[n]的最大值,所以前一个物品只需从后向前计算到f2[v-weight[n]]即可停止。以此类推第j个物品需要计算到f2[v-sum(weight[j]....weight[n])。此时又需要同cost取max,相见代码:)
- #include <stdio.h>
- #include <stdlib.h>
- #define MAXSIZE 2000
- #define MINIMUM -10000000;
- int cost[MAXSIZE];//数组下标从1开始
- int weight[MAXSIZE];//数组下标从1开始
- int f[200][MAXSIZE];
- int f2[MAXSIZE];
- int bag(int n, int v)//运用递归
- {//前n件物品恰放入一个容量为v的背包可以获得的最大价值
- int val=0;
- if (v<0)
- return MINIMUM;
- if (n==1 && v<cost[1])
- return 0;
- if (n==1 && v>=cost[1])
- return weight[1];
- val=max(bag(n-1, v-cost[n])+weight[n], bag(n-1, v));
- return val;
- }
- int bag2(int n, int v)//运用空间复杂度为O(n*v)递推
- {
- int i, j;
- for (i=0; i<=n; i++){//初始化
- for (j=0; j<=v; j++){
- f[i][j]=0;
- }
- }
- for (i=1; i<=n; i++){
- for (j=0; j<=v; j++){
- if (j>=cost[i])
- f[i][j]=max(f[i-1][j-cost[i]]+weight[i], f[i-1][j]);
- else
- f[i][j]=f[i-1][j];
- }
- }
- return f[n][v];
- }
- int bag3(int n, int v)//运用空间复杂度为O(n)递推
- {
- int i, j;
- for (i=0; i<=v; i++){//初始化
- f2[i]=0;
- }
- for (i=1; i<=n; i++){
- for (j=v; j>=cost[i]; j--){
- f2[j]=max(f2[j-cost[i]]+weight[i], f2[j]);
- }
- }
- return f2[v];
- }
- main(int argc, char *argv)
- {
- int N, V;
- int i, res;
- freopen("01.txt", "r", stdin);
- while (scanf("%d%d", &V, &N)!=EOF){
- for (i=1; i<=N; i++)
- scanf("%d%d", &cost[i], &weight[i]);
- res=bag(N, V);
- printf("%d/n", res);
- }
- }
- int bag3(int n, int v)//运用空间复杂度为O(n)递推
- {
- int i, j, sum=0, bound;
- for (i=0; i<=v; i++){//初始化
- f2[i]=0;
- }
- weight[0]=0;
- for (i=1; i<=n; i++){
- sum+=weight[i];
- }
- for (i=1; i<=n; i++){
- sum-=weight[i-1];
- bound=max(v-sum, cost[i]);
- for (j=v; j>=bound; j--){
- f2[j]=max(f2[j-cost[i]]+weight[i], f2[j]);
- }
- }
- return f2[v];
- }