【9925】0/1背包

来源:互联网 发布:plsql导出表数据 编辑:程序博客网 时间:2024/05/01 09:08

Time Limit: 1 second
Memory Limit: 128 MB

【问题描述】

一个旅行者有一个最多能用M公斤的背包,现在有n件物品,它们的重量分别是W1,W2,...,Wn,它们的价值分别为C1,C2,...,Cn.若
每种物品只有一件求旅行者能获得最大总价值。

【输入格式】

第一行:两个整数,M(背包容量,M<=200)和N(物品数量,N<=30);
第2..N+1行:每行二个整数Wi,Ci,表示每个物品的重量和价值。

【输出格式】

仅一行,一个数,表示最大总价值。

Sample Input

10 42  13  34  57  9

Sample Output

12

【法1】
设f[i][j]表示前i个物品,装的总重量不超过j时所获得的最大价值。
一开始初值都为0;
f[i][j] = max{f[i-1][j],f[i-1][j-w[i]]+c[i]};其中w[i]是第i个物品的重量,c[i]是第i个物品的价值。
f[i-1][j]表示不选第i个物品,d[i-1][j-w[i]] +c[i],表示选第i个物品。
前i个物品装的总重量不超过j可以由前i-1个物品,总重量不超过j-w[i] 再装一个物品 得到,这时候装了一个物品就变成不超过j了。
这是样例的模拟结果;
在第1个物品进行选择后:f[1][0]=0 f[1][1]=0 f[1][2]=1 f[1][3]=1 f[1][4]=1 f[1][5]=1 f[1][6]=1 f[1][7]=1 f[1][8]=1 f[1][9]=1 f[1][10]=1 


在第2个物品进行选择后:f[2][0]=0 f[2][1]=0 f[2][2]=1 f[2][3]=3 f[2][4]=3 f[2][5]=4 f[2][6]=4 f[2][7]=4 f[2][8]=4 f[2][9]=4 f[2][10]=4 


在第3个物品进行选择后:f[3][0]=0 f[3][1]=0 f[3][2]=1 f[3][3]=3 f[3][4]=5 f[3][5]=5 f[3][6]=6 f[3][7]=8 f[3][8]=8 f[3][9]=9 f[3][10]=9 

在第4个物品进行选择后:f[4][0]=0 f[4][1]=0 f[4][2]=1 f[4][3]=3 f[4][4]=5 f[4][5]=5 f[4][6]=6 f[4][7]=9 f[4][8]=9 f[4][9]=10 f[4][10]=12 

【代码1】
#include <cstdio>#include <cstring>int m,n,f[50][250],w[50],c[50];void input_data(){scanf("%d%d",&m,&n);for (int i = 1;i <= n;i++) //输入各个物品的信息 scanf("%d%d",&w[i],&c[i]);}void get_ans(){memset(f,0,sizeof(f));for (int i = 1;i <= n;i++) //枚举第i个物品 for (int j = m;j >= 0;j--) //枚举所占空间 {f[i][j] = f[i-1][j]; //表示第i个物品不拿 if (j >= w[i]) //如果第i个物品在当前所用空间情况下可以拿则尝试拿。 if (f[i-1][j-w[i]] + c[i] > f[i][j])f[i][j] = f[i-1][j-w[i]] + c[i];}}void output_ans(){printf("%d",f[n][m]);}int main(){input_data();get_ans();output_ans();return 0;}

【法二】
把二维换成一维的数组。
f[j]表示使用的容量不超过j时,所获得的最大利益。
f[j] = max{f[j],f[j-w[i]] + c[i]}
等于f[j]表示这个物品不选,f[j-w[i]] + c[i]则表示选了一个重量为w[i]的物品。
大家可以看一下f[j]数组的更新情况
在对第1号背包进行抉择之后:f[0]=0 f[1]=0 f[2]=1 f[3]=1 f[4]=1 f[5]=1 f[6]=1 f[7]=1 f[8]=1 f[9]=1 f[10]=1 


在对第2号背包进行抉择之后:f[0]=0 f[1]=0 f[2]=1 f[3]=3 f[4]=3 f[5]=4 f[6]=4 f[7]=4 f[8]=4 f[9]=4 f[10]=4 


在对第3号背包进行抉择之后:f[0]=0 f[1]=0 f[2]=1 f[3]=3 f[4]=5 f[5]=5 f[6]=6 f[7]=8 f[8]=8 f[9]=9 f[10]=9 


在对第4号背包进行抉择之后:f[0]=0 f[1]=0 f[2]=1 f[3]=3 f[4]=5 f[5]=5 f[6]=6 f[7]=9 f[8]=9 f[9]=10 f[10]=12 

可以和上面的二维进行对比,会发现是一样的。也就是说,其省略了一维的数组,却得到了相同的结果。
要注意这里的j这层循环一定要倒序
不然,如果有一个物品的重量为1
你更新完f[5],然后又更新f[6],又更新f[7]。。。只有一个物品。。你更新了好几次。(这个是完全背包??我不确定)
【代码2】
#include <cstdio>#include <cstring>int m,n,f[250],w[50],c[50];void input_data(){scanf("%d%d",&m,&n);for (int i = 1;i <= n;i++) //输入各个物品的信息 scanf("%d%d",&w[i],&c[i]);}void get_ans(){memset(f,0,sizeof(f));for (int i = 1;i <= n;i++) {for (int j = m;j >= w[i];j--) //注意一定要倒序枚举,原因我在题解里面讲了。认真体会下。 if (f[j-w[i]] + c[i] > f[j])f[j] = f[j-w[i]] + c[i];} }void output_ans(){printf("%d",f[m]);}int main(){input_data();get_ans();output_ans();return 0;}


0 0
原创粉丝点击