题目链接
题意:一开始给定初始的r,和n件物品,每种物品有两个属性ai和bi,当r大于等于ai时可以拿这件物品,但拿的同时r会加上bi(bi可能为负数),问最多能拿几件。
思路:bi会正数的话很容易考虑先按ai从小到大排列,看看最多能拿几件(这里就是贪心思想),那么bi小于0的时候呢?我们可以把bi小于0的物品按ai+bi的和从大到小排列,然后就是经典背包模型,dp【i】【j】表示选了前i件物品,背包容量为j时的个数。
#include<bits/stdc++.h>
using namespace std;
struct node{
int a,b;
bool operator <(const node &t)const{
return a>t.a;
}
};
bool cmp(const pair<int,int>&a,const pair<int,int>&b)
{
return a.first+a.second>b.first+b.second;
}
vector<pair<int,int>>v;
priority_queue<node>q;
int n,r,t1,t2,cnt,ans=0,dp[201][40001];
int main()
{
scanf("%d%d",&n,&r);
for(int i=1;i<=n;++i)
{
scanf("%d%d",&t1,&t2);
if(t2<0) v.push_back({t1,t2});
else q.push({t1,t2});
}
while(!q.empty())
{
int t=q.top().a;
if(r<t) break;
cnt++;
r+=q.top().b;
q.pop();
}
sort(v.begin(),v.end(),cmp);
memset(dp,0,sizeof(dp));
for(int i=0;i<v.size();++i)
{
for(int j=0;j<=r;++j)
{
if(j>=v[i].first&&j+v[i].second>=0)
dp[i+1][j+v[i].second]=max(dp[i+1][j+v[i].second],dp[i][j]+1);//合法状态
dp[i+1][j]=max(dp[i+1][j],dp[i][j]);//不合法
}
}
for(int i=0;i<=r;++i) ans=max(ans,dp[v.size()][i]);
printf("%d\n",ans+cnt);
}