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

博客详细介绍了如何处理Codeforces 1203F2问题中b值小于0的项目,采用贪心策略,按a值从大到小排序,检查每个项目能否完成。如果不能完成,判断是否可以替换已完成的项目,并选择替换后使r值最大的那个。同时解释了为何替换后某些原本无法完成的项目可能会变得可以完成,并阐述了这些项目应如何正确处理。
摘要由CSDN通过智能技术生成

传送门

思路:

首先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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值