完全背包问题

题目链接

题意:在01背包的基础上多了每个物品都可以无限取的条件

思路:首先考虑在01背包的基础上的暴力枚举,我们可以在枚举前i件物品最多拿j的容量时再遍历当前物品拿的数量

贴一个暴力tle代码:

#include
#define endl '\n'
#define ll long long
#define INF 0x3f3f3f3f
#define pb push_back
#define int long long
#define Mirai ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
using namespace std;
typedef pair pii;
const int N=1010;
int dp[N][N];
int n,m,v,w;
void solve()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)//枚举拿前i件物品
	{
		cin>>v>>w;
		for(int j=0;j<=m;j++)//枚举最大容量
		{
			for(int k=0;k*v<=j;k++)//枚举每一个物品拿多少个
			{
				dp[i][j]=max(dp[i][j],dp[i-1][j-k*v]+k*w);
                //此处有k=0的情况,dp[i][j]会首先等于dp[i-1][j]
			}
		}
	}
	cout<>T;
	while(T--)
	{
		solve();
	}
}

dp[i][j]=max(dp[i-1][j],dp[i-1][j-v]+w,dp[i-1][j-2*v]+2*w,...)

dp[i][j-v]=max(dp[i-1][j-v],dp[i-1][j-2*v]+w,dp[i-1][j-3*v]+2*w,...)

所以不难发现dp[i][j]中取max的第二项之后的部分都可以转化为dp[i][j-v]+w

所以可得状态转移方程:dp[i][j]=max(dp[i-1][j],dp[i][j-v]+w);

而此时我们同样发现每一层的状态只与i-1层的状态有关,所以仍然可以用01背包的降维优化方式,注意此时需要的状态是更新之后j的左值,所以需要从左往右遍历,而注意如果当前容量不足以装下当前物品,仍然是不需要更新的,所以枚举范围为v[i]~m

ac代码:

#include
#define endl '\n'
#define ll long long
#define INF 0x3f3f3f3f
#define pb push_back
#define int long long
#define Mirai ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
using namespace std;
typedef pair pii;
const int N=1010;
int n,m,v,w;
int dp[N];
void solve()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		cin>>v>>w;
		for(int j=v;j<=m;j++)
		{
			dp[j]=max(dp[j],dp[j-v]+w);
		}
	}
	cout<>T;
	while(T--)
	{
		solve();
	}
}

你可能感兴趣的:(动态规划,动态规划)