多重背包问题 I
朴素:
[AcWing] 4. 多重背包问题 I(C++实现)多重背包问题 I模板题
以上只看推导思路,代码看下面
时间复杂度:
O ( n m s ) O(nms) O(nms)
代码实现:
#include<bits/stdc++.h>
using namespace std;
int n, m;
const int N = 110;
int v, w, s;
int dp[N][N];
int main()
{
cin>>n>>m;
for(int i=1;i<=n;++i)
{
cin>>v>>w>>s;
for(int j=0;j<=m;++j)
{
for(int k=0; k*v<=j&&k<=s; ++k)
{
dp[i][j] = max(dp[i][j], dp[i-1][j-k*v]+k*w);
}
}
}
cout<<dp[n][m]<<endl;
return 0;
}
多重背包问题 II
数据范围相对于 I 扩大了10
倍
二进制优化:
数据规模较大,如果按之前的朴素做法O(nms)
超时,应当优化
我们采用二进制优化,由于第i
种物品有若干个,因此将每一种物品中的多个物品打包成一件新的物品,
例如:第i
种物品有200
个,则打包成8
份,第一份1
个,第二份2
个,第三份4
个,依次8
,16
,32
,64
此时已经有127
个了,还剩200-127=73
个第i
种物品
用若干份新的物品代替原来第i
种物品,后枚举新的物品选or不选(01背包本质),就可拼凑出第i
个物品所有方案
优化之后,对于若干新的物品运用01背包办法解决
时间复杂度:
O ( n m l o g s ) O(nmlogs) O(nmlogs)
#include<bits/stdc++.h>
using namespace std;
const int N = 15000; //N*logs(注意是以2为底,s的对数)=1000*log2000≈11000,开15000保险
const int M = 2010;
int n,m;
int v[N],w[N];
int dp[N]; //01背包优化,用一维数组
int main()
{
int a,b,s;
cin>>n>>m;
int cnt=0; //存储新物品的编号
//多重背包二进制优化操作
for(int i=1;i<=n;++i)
{
cin>>a>>b>>s; //第i种物品的体积,价值,数量
int k=1;
while(k<=s) { v[++cnt]=a*k, w[cnt]=b*k, s-=k, k<<=1; }
if(s>0) { v[++cnt]=a*s, w[cnt]=b*s; }
}
//01背包
n=cnt; //更新物品数量,此时为若干个新物品
for(int i=1;i<=n;++i)
{
for(int j=m;j>=v[i];--j)
dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
}
cout<<dp[m]<<endl;
return 0;
}