Codeforces Round #579 (Div. 3) F2. Complete the Projects (hard version)(背包dp+优先队列)

题目链接
在这里插入图片描述
在这里插入图片描述
题意:一开始给定初始的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); 
}
发布了171 篇原创文章 · 获赞 0 · 访问量 5806

猜你喜欢

转载自blog.csdn.net/qq_42479630/article/details/104590565