经典问题之多重背包的总结与提升
来源:互联网 发布:同花顺中天软件下载 编辑:程序博客网 时间:2024/06/05 04:12
多重背包:
1.基础题型
伪代码:
i=1 to n
j=1 to W
k=1 to m[i]
f[j]=max{f[j-k*w[i]]+k*v[i]}
2.加强版
(一)对于数据不是特别紧的可采用二进制法,效率O(nW log m)
解析:对于每个m[i],我们可以分解成2^0+2^1+2^2...+2^k+a(a为m[i]完全分解出来多的),我们知道1,2,4.。。。2^k,可以表示出1到2^(k+1)-1的所有数,也就是说把物品分解后的多重背包就转化成了01背包,效率可以达到(nW),总效率还需乘上log m(分解后多出的物品数)
参考程序:
#include<cstdio>#include<algorithm>#define maxn 11000#define maxw 11000using namespace std;int dp[maxw];int m[maxn],w[maxn],v[maxn];int main(){freopen("hallow.in","r",stdin);freopen("hallow.out","w",stdout);int n,W;scanf("%d%d",&n,&W);for (int i=0;i<n;i++)scanf("%d%d%d",&m[i],&w[i],&v[i]);for (int i=0;i<n;i++){int num=m[i];for (int k=1;num>0;k<<=1){int mul=min(k,num);for (int j=W;j>=w[i]*mul;j--){dp[j]=max(dp[j],dp[j-w[i]*mul]+v[i]*mul);}num-=mul;}}printf("%d",dp[W]);return 0;}
(二)对于上述方法都不可以解决的题目,就需要单独队列维护,理论效率为O(nW),经过检验成立。
解析:再分析转移方程式:f[j]=max(f[j-k*w[i]]+k*v[i]}(0<=k<=m[i])
可以看出,如果j mod w[i]取值不同,则其方程式是相互独立的,先设j mod w[i]=c,每个c的做法相同,我们就取c=0的特殊值来研究,其他的c同理即可。
设a[j]=dp[i][j*w[i]]
则f[(j+k)*w[i]]=max{a[j]+k*v[i],a[j+1]+(k-1)*v[i],...,a[j+k]}
因为k是变动的,所以max{}中的常数项不能有k,则提出(j+k)*v[i],原式可化为:
f[(j+k)*w[i]]=max{a[j],a[j+1]-(j+1)*v[i],...a[j+k]-(j+k)*v[i]}+(j+k)*v[i]
当我们在求f[(j+k)*w[i]]时,明显f[(j+k-1]*w[i]]已经求出,而f[(j+k-1)*w[i]]仅仅是比f[(j+k)*w[i]]的开始多一项,结尾少一项,所以我们可以想到滑动窗口,于是就可以用单调队列维护a[j]-j*v[i]的最大值,于是就可以用O(1)的时间转移到新的状态。
伪代码:
i=1 to n
c=0 to w[i]
while(j*w[i]+a<=W(j++))
队列维护
参考程序:
#include<cstdio>#include<algorithm>#define maxn 2500#define maxv 1000using namespace std;int dp[maxv+1];int deq[maxv+1];int deqv[maxv+1];int n,V;int m[maxn],w[maxn],v[maxn];int main(){freopen("hallow.in","r",stdin);freopen("hallow.out","w",stdout);scanf("%d%d",&n,&V);for (int i=0;i<n;i++)scanf("%d%d%d",&m[i],&w[i],&v[i]);for (int i=0;i<n;i++){for (int a=0;a<w[i];a++){int s=0,t=0;for (int j=0;j*w[i]+a<=V;j++){int val=dp[j*w[i]+a]-j*v[i];while(s<t && deqv[t-1]<=val)t--;deq[t]=j;deqv[t++]=val;dp[j*w[i]+a]=deqv[s]+j*v[i];if (deq[s]==j-m[i]){s++;}}}}printf("%d",dp[V]);return 0;}
- 经典问题之多重背包的总结与提升
- HDU 2191 背包问题之多重背包
- 背包九讲之多重背包问题
- 数据结构经典算法学习之多背包问题
- HDU 2844 Coins 背包问题之多重背包
- dp2之多重背包
- 背包探索之多重背包
- 背包dp之多重背包
- 经典问题之01与完全背包总结
- 动态规划之多重背包
- 背包九讲之多重背包 Java
- 经典的01背包问题
- 经典的01背包问题
- 经典的01背包问题
- 经典的01背包问题
- 数据挖掘总结之多重共线性与过拟合
- HDU汶川512之多重背包
- 打牌第三天之多重背包
- mport 做html公共模块导入操作
- Linux下格式化U盘及分区
- IOS判断是否是URL
- sql语句中GROUP BY 和 HAVING的使用
- 单向透视玻璃
- 经典问题之多重背包的总结与提升
- U3D之aabb.IsValid()、IsFinite(outDistanceForSort)、IsFinite(outDistanceAlongView),u3disfinite
- JS利用windows.open()打开子窗口
- 零基础学习PHP笔记【三】数据库操作--邮件列表
- sql语句中having的使用例子
- 数据篇之JDBC连接MySQL
- OkHttp
- 数字转字符串前面自动补0 / 字符串(数字串)除去前面的0
- maven update web工程报错