int max(const int a,const int b){
return a>b ? a:b;}
int main(){
int w[35]={0},v[35]={0},dp[210]={0}; int n,m;
scanf(\"%d %d\ int i,j;
for(i=1;i<=n;i++){
scanf(\"%d %d\ }
for(i=1;i<=n;i++){ for(j=0;j<=m;j++){
if(j>=w[i])//如果当前背包的容量⼤于商品的质量 {
dp[j]=max(dp[j],dp[j-w[i]]+v[i]);//判断是否应该拿下 } }
for(int k=0;k<=m;k++) {
printf(\"%d \ }
printf(\"\\n\"); }
printf(\"%d\\n\}
通过以上代码的输出可以看出打印的dp表和我们推测的并没有什么区别,程序正确!
多重背包问题
题⽬描述:
为了庆祝班级在校运会上取得了全校第⼀名的好成绩,班主任决定开⼀场庆功会,为此拨款购买奖品犒劳运动员。期望拨款⾦额能够购买最⼤价值的奖品,可以补充他们的精⼒和体⼒。输⼊:
第⼀⾏输⼊两个数n(n<=500),m(m<=6000),其中n代表希望购买的奖品的种数,m表⽰拨款⾦额。
接下来的n⾏,每⾏3个数,w,v,s分别表⽰第i种奖品的价格、价值(价格与价值是不同的概念)和能购买的最⼤数量(买0件到s件均可),其中w<=100,v<=1000,s<=10;输出:
⼀⾏:⼀个数,表⽰此次购买能获得的最⼤价值(注意!不是价格)。⽰例:
输⼊:5 1000输出:80 20 440 50 930 50 740 30 6
20 20 1
与完全背包不同的是:完全背包每个物品的个数是⽆限的,⽽多重背包是每个物品只能拿指定的件数。那么最容易想到的⽅法就是把相同的物品分开,⽐如说有n个a物品,就将它分成a1 a2 a3 a4…an然后⽤01背包的⽅法去解决。那么我们就可以写出以下核⼼代码:
for(i=1;i<=n;i++){ for(j=m;j>=0;j--){
for(k=0;k<=s[i]&&j>=k*w[i];k++) {
dp[j]=max(dp[j],dp[j-k*w[i]]+k*v[i]);//从01背包的状态转移⽅程,去增加第i个物品拿k个的循环 } }}
通过以上的代码可以看出当s[i]特别⼤的时候那么就会消耗⾮常多的时间复杂度,那么肯定是有优化的⽅法的!那么我们可以通过⼆进制来对这个同⼀个物品应该拿取⼏个进⾏优化。我们可以通过以下问题进⾏研究:
有1000个苹果,10个箱⼦怎么放,不管我想拿多少个苹果,都可以成箱成箱的拿?
⽤⼆进制的思想就是每⼀个箱⼦代表⼆进制对应的位数,那么210⼤于1024应该是可以满⾜题⽬条件的。那么每个箱⼦放的苹果分别是1,2,4,8,16,32,…488(1000-512)。需要⼀个苹果拿第⼀箱,需要两个苹果拿第⼆项,需要三个苹果拿⼀⼆箱。那么对于需要拿1000箱的问题本来要循环1000次,经过优化以后只⽤循环10次就可以啦!那么我们就可以写出以下程序啦!
for(i=1;i<=n;i++){ for(j=m;j>=0;j--){
for(k=0;k<=s[i]&&j>=k*w[i];k<<=1) {
if((k<<1)>s[i]&&j>=k*w[i]) {
dp[j]=max(dp[j],dp[j-(s[i]-k)*w[i]]+(s[i]-k)*v[i]); }
else
dp[j]=max(dp[j],dp[j-k*w[i]]+k*v[i]);//从01背包的状态转移⽅程,去增加第i个物品拿k个的循环 } }}
动态规划解题思路
对于动态规划问题我们⼀般的思路如下:
判断是动态规划的解题思路以后⽴马定义⼀个数组,把数组对应的下标、对应的值想清楚。然后根据题⽬意思找规律进⾏打表,找出初始状态以及⼀些边界条件。根据打表的数据找出状态转移⽅程。最后根据状态转移⽅程进⾏编写程序。
到此这篇关于C语⾔动态规划之背包问题详解的⽂章就介绍到这了,更多相关C语⾔ 背包内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!