题目链接
题意:在01背包的基础上多了每个物品都可以无限取的条件
思路:首先考虑在01背包的基础上的暴力枚举,我们可以在枚举前i件物品最多拿j的容量时再遍历当前物品拿的数量
贴一个暴力tle代码:
#include<bits/stdc++.h>
#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<int,int> 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<<dp[n][m]<<endl;
}
signed main()
{
Mirai;
int T=1;
//cin>>T;
while(T--)
{
solve();
}
}
所以不难发现dp[i][j]中取max的第二项之后的部分都可以转化为dp[i][j-v]+w
所以可得状态转移方程:
而此时我们同样发现每一层的状态只与i-1层的状态有关,所以仍然可以用01背包的降维优化方式,注意此时需要的状态是更新之后j的左值,所以需要从左往右遍历,而注意如果当前容量不足以装下当前物品,仍然是不需要更新的,所以枚举范围为v[i]~m
ac代码:
#include<bits/stdc++.h>
#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<int,int> 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<<dp[m]<<endl;
}
signed main()
{
Mirai;
int T=1;
//cin>>T;
while(T--)
{
solve();
}
}