HDU 3591 The trouble of Xiaoqian 混合背包(完全背包和多重背包混合)
来源:互联网 发布:万网域名续费多少钱 编辑:程序博客网 时间:2024/06/14 02:18
传送门:HDU 3591
题目大意:小倩去买一件价值为 t 东西,她有 n 种钱币,第i种价值为 Vi,数量为 Ci。售货员那也有这 n 种货币,但是数量无限。如果小倩付款给的价值大于 t,售货员就要找零。问小倩需要带的货币数加上售货员找零的钱币数的最小和是多少。
3 705 25 505 2 10 0
Case 1: 3
首先给大家推荐一个很不错的题解:HDU 3591题解。
思路:既然让求两者和最小,则分别求出最小值相加就可以了。很明显,我们应该将价值 t 看作背包的容量,而物品的花费和价值只告诉了一个——每种物品的价值 Vi。我们要求的是数量的最小值。所以我们应该做一下转换,把数量看作装入该物品可以获得的奖励,把物品的价值看作装入该物品的花费。
对于小倩来说,钱币数量有限制,应该用多重背包(dp1)解决。其思路是如果某种物品的总花费大于等于m(Vi * Ci>=m),则相当于该物品有无数件,转化为多重背包解决。反之,转化为01背包解决。也就是将该种物品拆分成单个物品,但是这样时间复杂度很高,所以转化为先拆出1个,如果还可以拆,再拆出2个,4个,8个……即2的 i 次幂个,将拆出的 2^i 个物品看成一个物品。我称之为倍增法。如果剩下的不足 2^i 个,则它们单独看成一个。
例如:13,先拆出1个,剩余12个;再拆出2个,剩余10个;再拆出4个,剩余6个;再拆出8个,发现不够了,这6个看作同一个物品。
当将 num 个物品看成一个物品时,其花费为其总价值 num*Vi,其钱币数量或者说奖励为 num。
对于售货员来说,钱币数量无限制,应该用完全背包(dp2)解决。加入1个某种物品,花费为其价值 Vi,钱币数量或者说奖励为 1,因为加入的是1个。
具体实现:输入后,对于第 i 种物品分别跑一遍多重背包和完全背包,分别表示小倩和售货员使用的钱币的最小数。假设小倩付款 a 元,售货员找零 b 元,则有 a-b=t。所以答案就是 max( dp1[a] + dp2[a-t] )。
注意:
1.当无法通过购买找零得到价值 t 时,输出 -1,并且前面也要带 “Case x:”,被这个地方坑过一次。
2.由于是求最小值,所以背包中的max要改为min,初始化时除了 dp[0],其他都设为无穷大,这样也保证了是正好能装满该背包时候的最小值。
3.求解背包时的容量上限不是价值 t ,而是最大值 20000,因为小倩付得钱可能比 t 大。
4.在多重背包转化为完全背包的代码中,有句 cnt*wt>=t ,改为 cnt*w>=20000 也可以。个人感觉从想法上应该写第一种。
#include<stdio.h>#include<string.h>#define inf 0x3f3f3f3fint t,dp1[20010],dp2[20010];int min(int a,int b){if(a<b) return a;else return b;}//01背包,prz为奖励(价值),wt为花费(重量)void ZOP(int dp[],int prz,int wt){int j;for(j=20000;j>=wt;j--) //注意循环的上限是20000,而不是t dp[j]=min(dp[j],dp[j-wt]+prz);}//完全背包,prz为奖励(价值),wt为花费(重量)void CP(int dp[],int prz,int wt){int j;for(j=wt;j<=20000;j++) //注意循环的上限是20000,而不是tdp[j]=min(dp[j],dp[j-wt]+prz);}//多重背包,wt为花费(重量),cnt为物品数量 void MP(int dp[],int wt,int cnt){//该处可以改为 cnt*wt>=20000 if(cnt*wt>=t) CP(dp,1,wt); //转换为完全背包 else //转换为01背包,类似于倍增的思想 { int k=1;while(k<=cnt){ZOP(dp,k,wt*k); //耗费为物品总价值,奖励为物品数量 cnt-=k;k<<=1;}if(cnt>0) ZOP(dp,cnt,wt*cnt);}}int main(){int i,j,n,ans,cas,v[110],c[110];cas=1;while(~scanf("%d%d",&n,&t)&&n&&t){for(i=1;i<=n;i++) scanf("%d",&v[i]);for(i=1;i<=n;i++) scanf("%d",&c[i]);memset(dp1,inf,sizeof(dp1));memset(dp2,inf,sizeof(dp2));dp1[0]=0;dp2[0]=0;for(i=1;i<=n;i++){MP(dp1,v[i],c[i]);CP(dp2,1,v[i]);}ans=inf;for(i=t;i<=20000;i++)ans=min(ans,dp1[i]+dp2[i-t]);if(ans==inf) printf("Case %d: -1\n",cas++);else printf("Case %d: %d\n",cas++,ans);}return 0;}
- HDU 3591 The trouble of Xiaoqian 混合背包(完全背包和多重背包混合)
- hdu 3591 The trouble of Xiaoqian(多重背包+完全背包)
- hdu 3591 The trouble of Xiaoqian ( 多重背包 + 完全背包 )
- hdu 3591 The trouble of Xiaoqian 多重背包+完全背包
- HDU 3591 The trouble of Xiaoqian(多重背包+完全背包)
- hdu 3591 The trouble of Xiaoqian 多重背包+完全背包。。。
- HDU 3591 The trouble of Xiaoqian (多重背包+完全背包)
- The trouble of Xiaoqian(混合背包)
- HDU 3591 The trouble of Xiaoqian (多重背包+完全背包)
- hdu 3591 The trouble of Xiaoqian( 多重背包+完全背包)
- hdu 3591 The trouble of Xiaoqian 多重背包(二进制)+完全背包!
- hdu3591 The trouble of Xiaoqian(多重背包 + 完全背包)
- HDU3591:The trouble of Xiaoqian(多重背包+完全背包)
- hdu 3591 The trouble of Xiaoqian(多重背包)
- HDU3591 - The trouble of Xiaoqian(多重背包+完全背包)
- hdu 3591The trouble of Xiaoqian (多重背包)
- HDU 3591.The trouble of Xiaoqian【完全背包+多重背包】【4月24】
- hdu3591The trouble of Xiaoqian 多重背包+完全背包
- 常用的正则表达式
- 【转载】APP瘦身之webp实践
- Spark中Task,Partition,RDD、节点数、Executor数、core数目的关系
- hls多码率适应
- plsql查看是否锁表,锁模式等,以及解锁SQL
- HDU 3591 The trouble of Xiaoqian 混合背包(完全背包和多重背包混合)
- thinkphp3.2.0 设置错误页面指向 404
- 通过下载lrzsz的tar包,实现rz命令上传本地文件
- JavaSE、JavaEE、JavaWeb分不清?
- WebSocket简单介绍
- linux下查找命令which/whereis/locate/find的对比和总结
- 为什么在Python里推荐使用多进程而不是多线程?
- Linux sed查看某时间段的系统日志
- java线程池概述