目录
问题描述:有n种物品,每个物品的数目是1,价值是w,体积是v,有一个容量V的书包,问书包所能装的最大价值是多少?
从大到小枚举,原因:一维的转移方程实际上是由二维演变过来,对于每个物品,有取和不取两种取法,当枚举到第i个物品时,他只由dp [ i-1]转移,所以说,前面的dp(1~i-2)是不需要的,原理如图:
问题描述:有n种物品,每种物品的数目是无限个,价值是w,体积是v,有一个容量V的书包,问书包所能装的最大价值是多少?
从小到大枚举,理由如上图,如果从小到大枚举相当于之前的状态可多次选取。
问题描述:有n种物品,每种物品的数目s,价值是w,体积是v,有一个容量V的书包,问书包所能装的最大价值是多少?
二进制拆分,拆分出来的数可以组成,0~这个数之间的所有数。然后问题就转换为01背包了。
using namespace std;
vectorans;
int dp[1010];
int main()
{
int n,V;
cin>>n>>V;
for(int i=1;i<=n;i++)
{
int v,w,s;
cin>>v>>w>>s;
for(int k=1;k<=s;k*=2)
{
s-=k;
ans.pb(mk(k*v,k*w));
}
ans.pb(mk(s*v,s*w));
}
for(auto it : ans)
{
for(int i=V;i>=ans.first;i--)
dp[i] = min(dp[i],dp[i-ans.first]+ans.second);
}
cout<
问题描述:前面三种物品的混合。
首先把多重背包二进制拆分成01背包存到vector中,那么此时物品种类只有两种,枚举物品,如果这个物品是01背包,从大到小枚举,否则从小到大枚举。
using namespace std;
struct node {
int type,v,w;
};
vectorans;
int dp[1010];
int main()
{
int n,V;
cin>>n>>V;
for(int i=1;i<=n;i++)
{
int v,w,s;
cin>>v>>w>>s;
if(s == -1)ans.pb({-1,v,w});
else if(s == 0)ans.pb({0,v,w});
else
{
for(int k=1;k<=s;k*=2)
{
s-=k;
ans.pb({-1,v*k,w*k});
}
ans.pb({-1,s*v,s*w});
}
}
for(auto it : ans)
{
if(it.type == -1)
{
for(int i=V;i>=it.v;i--)dp[i] = max(dp[i],dp[i-it.v]+it.w);
}
else
{
for(int i=it.v;i<=V;i++)dp[i] = max(dp[i],dp[i-it.v]+it.w);
}
}
cout<
每组物品有若干个,组内物品互斥,每组中的只能选择一个,求背包的总价值。
三重循环,枚举每一组中的所有物品,对于这组内的每个物品,都由上一组转移。
所以过程就是,首先枚举组,然后枚举转移的状态,然后枚举组内的物品,复杂度是n^3.
using namespace std;
vectorG[105];
int v[1005],w[1005],d[1005];
int main()
{
int V,n,mm=0;
scanf("%d%d",&V,&n);
for(int i=1;i<=n;i++)
{
int x;
cin>>v[i]>>w[i]>>x;
G[x].push_back(mk(v[i],w[i]));
mm=max(mm,x);
}
for(int i=1;i<=mm;i++)
{
for(int j=V;j>=0;j--)
{
for(auto it : G[i])
{
if(j>=it.first)d[j]=max(d[j],d[j-it.first]+it.second);
}
}
}
cout<
问题描述:背包的限制不止有体积,还有重量。
拓展维度,01背包从大到小枚举两个限制,完全背包从大到小。
using namespace std;
int dp[1010][1010];
int main()
{
int n,V,M;
cin>>n>>V>>M;
for(int i=1;i<=n;i++)
{
int v,m,w;
cin>>v>>m>>w;
for(int j=V;j>=v;j--)
for(int k=M;k>=m;k--)
dp[j][k] = max(dp[j][k],dp[j-v][k-m]+w);
}
cout<