Codeforces 1203F2 Complete the Projects (hard version) 贪心

传送门

思路:

首先b>=0的项目不难处理,根据a值从小到大排序,能完成则r+=b[i]即可.关键是在于处理b<0的项目.

对于b<0的项目采用贪心策略:

先根据a值从大到小排序,每遍历到一个,就看它是否可以完成,如果可以,r+=b[i]并且标记i为完成状态. 如果不可以,看它是否可以替换之前已经完成的项目.假设j是某个之前已经完成的项目,i为当前不可完成项目,替换的条件为r-b[j]>=a[i]&&r-b[j]+b[i]>=0&&b[j]<=b[i],那么对于多个可以替换的项目,应该选哪个进行替换? 肯定是选替换后可以使r的值最大的那个,设i要替换j.替换完之后, 有一些不可完成的项目又变得可以完成了(最多只会有一个这样的项目,请仔细考虑,因为之前不可以完成的项目,肯定是因为它的b值太小了,它替换掉任意一个已经完成的项目都会使得r减小.而且这个项目必须要放在i的下一个去完成,如果放在i的前面,会导致未解决i之前的r值变得更小,就更无法解决i了,还有可能会影响i之前那些已经完成的任务.例如,j已经完成,i不能完成,现在i要替换j,有一个k是未完成的状态,我们现在想完成这个k必须将k放在i之后完成,如果k放在i之前完成,必定导致i不可能完成,因为k之所以是未完成状态,是因为k比j的b要小,所以如果不去完成j,而是先完成k,再去完成i,势必导致i不可以完成),所以再遍历i-1到1,找出之前没被完成但现在可以完成了并且使得剩余的r最大的那个项目,设置为完成状态.

 

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <string>
#include <queue>
#include <cmath>
#include <stack>
#include <time.h>
#include <map>
#include <set>
using namespace std;
struct Node{
	int a,b;
}node[105],node1[105];
int book[105];
bool cmp(Node a,Node b){
	return a.a<b.a;
}
bool cmp1(Node a,Node b){
	return a.a>b.a;
}
 
int main(){
	int n,r;
	scanf("%d%d",&n,&r);
	
	int cnt=0,cnt1=0;
	int num=0;
	for(int i=1;i<=n;i++){
		int a,b;
		cin>>a>>b;
		if(b>=0){
			node[++cnt].a=a;
			node[cnt].b=b;
		}
		else{
			node1[++cnt1].a=a;
			node1[cnt1].b=b;
		}
	}
	sort(node+1,node+cnt+1,cmp);
	sort(node1+1,node1+cnt1+1,cmp1);
	for(int i=1;i<=cnt;i++){
		if(r<node[i].a){
			break;
		}
		num++;
		r+=node[i].b;
	}
	for(int i=1;i<=cnt1;i++){
		if(node1[i].a<=r&&r+node1[i].b>=0){
			num++;
			r+=node1[i].b;
			book[i]=1;
			continue;
		}	
		int id=0;
		int maxn=r;
		for(int j=i-1;j>=1;j--){
			if(book[j]){
				int t=r-node1[j].b;
				if(node1[i].a<=t&&t+node1[i].b>=0){
					if(maxn<t+node1[i].b){
						maxn=t+node1[i].b;
						id=j;
					}
				}	
			}
		}
		if(id==0)continue;
		r=maxn;
		book[i]=1;
		book[id]=0;
		id=0;
		maxn=0;
		for(int j=i-1;j>=1;j--){
			if(book[j]==0){
				if(r>=node1[j].a&&r+node1[j].b>=0){
					if(id==0||maxn<r+node1[j].b){
						id=j;
						maxn=r+node1[j].b;
						
					}
				}
			}
		}
		if(id==0)continue;
		book[id]=1;
		num++;
		r=maxn;
	}
	printf("%d\n",num);
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值