Eden的新背包问题 题解

版权声明:八月炊火的博客如需转载请注明出处 https://blog.csdn.net/qq_34990731/article/details/83385131

题目
知识点: 多重背包DP
讲解:
对于这一题其实就是多重背包的变式问题,我们发现就是在多重背包问题上加上了有一种不可以选,我们思考一下去掉这个物品不能选后会怎么改变,也就是把原本连续的一串物品分成了两块,而我们如果正常地做多重背包的话只能计算出前面一段,后面怎么办?
再从后往前DP一遍不就好了,对就这么简单,只要想到了这里,那么问题就变成了多重背包版子题了。
代码:

#include<iostream>
#include<cstdio>
using namespace std;
struct wanju
{
	int v,w,num;//v是价值,w是重量,num是数量 
}AK[1100];
int n,dp1[1100][1100],dp2[1100][1100];
void work()
{
	for(int i=1;i<=n;i++)//从前往后DP 
	{
		for(int j=0;j<=1000;j++) 
			dp1[i][j]=dp1[i-1][j];//初始化 
		int much=AK[i].num;//因为后面的又一遍DP还要用到数量所以我们开个变量存一下 
		for(int j=1;j<=much;j=j<<1)//二进制分解物品 
		{
			for(int k=1000;k>=j*AK[i].w;k--)//分解后直接计算 
				dp1[i][k]=max(dp1[i][k],dp1[i][k-AK[i].w*j]+AK[i].v*j);
			much-=j;
		}
		if(much>0)//分解后还有剩下 
		{
			for(int j=1000;j>=much*AK[i].w;j--)//在把剩下的看做一个物品计算 
				dp1[i][j]=max(dp1[i][j],dp1[i][j-much*AK[i].w]+AK[i].v*much);
		}
	}
	for(int i=n;i>=1;i--)//从后往前DP,顺序改变其他不变 
	{
		for(int j=0;j<=1000;j++) 
			dp2[i][j]=dp2[i+1][j];
		int much=AK[i].num;
		for(int j=1;j<=much;j=j<<1)
		{
			for(int k=1000;k>=j*AK[i].w;k--)
				dp2[i][k]=max(dp2[i][k],dp2[i][k-AK[i].w*j]+AK[i].v*j);
			much-=j;
		}
		if(much>0)
		{
			for(int j=1000;j>=much*AK[i].w;j--)
				dp2[i][j]=max(dp2[i][j],dp2[i][j-much*AK[i].w]+AK[i].v*much);
		}
	}
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d %d %d",&AK[i].w,&AK[i].v,&AK[i].num);//读入每个物品 
	work();//预处理计算 
	int q;
	scanf("%d",&q);
	while(q--)
	{
		int x,y,ans=0;
		scanf("%d %d",&x,&y);
		for(int i=0;i<=y;i++)//我们i表示分i个容量给前半段,剩下的给后半段 
			ans=max(ans,dp1[x][i]+dp2[x+2][y-i]);//计算最大值,因为玩具是从0开始编号,我们代码是从1开始编号,所以x相当于x+1 
		printf("%d\n",ans);
	}
	return 0;
}

如果有问题欢迎留言。
希望大家都可以AC。

猜你喜欢

转载自blog.csdn.net/qq_34990731/article/details/83385131