P4053 [JSOI2007]建筑抢修

P4053 [JSOI2007]建筑抢修

题目描述

小刚在玩JSOI提供的一个称之为“建筑抢修”的电脑游戏:经过了一场激烈的战斗,T部落消灭了所有z部落的入侵者。但是T部落的基地里已经有N个建筑设施受到了严重的损伤,如果不尽快修复的话,这些建筑设施将会完全毁坏。现在的情况是:T部落基地里只有一个修理工人,虽然他能瞬间到达任何一个建筑,但是修复每个建筑都需要一定的时间。同时,修理工人修理完一个建筑才能修理下一个建筑,不能同时修理多个建筑。如果某个建筑在一段时间之内没有完全修理完毕,这个建筑就报废了。你的任务是帮小刚合理的制订一个修理顺序,以抢修尽可能多的建筑。

输入输出格式

输入格式:

第一行是一个整数N,接下来N行每行两个整数T1,T2描述一个建筑:修理这个建筑需要T1秒,如果在T2秒之内还没有修理完成,这个建筑就报废了。

输出格式:

输出一个整数S,表示最多可以抢修S个建筑.


首先我们的、肯定是要求要求这个工人一开始就开始干,一直马不停蹄的干。这才是最优的。

可是要如何安排捏?

我们肯定是贪心的安排。如果当前时间比一个计划的最晚开始时间还早。我们肯定立马就干。

可是如果不是呢?

我们只有两种操作:1放弃 2.干

干的话我们就要放弃最多一个前面的任务,一定是最多。要是大于1个的话,我们为什么要干呢?

同样都是任务,我们放弃哪一个呢?肯定是放弃时间最长的好不好。 (这也就是反悔)

然后我们的算法流程就出来了

1.先将输入的数据按照自爆时间升序排序

2.扫描一遍,若满足当前时间小于最晚开始时间,累加

不满足,选一个已完成的任务中最大完成时间,将其所用时间返还,在判断是否合法

#include<algorithm>
#include<queue>
const int maxn=151000;
using std::sort;
using std::priority_queue;
priority_queue<long long>q;
struct node
{
	long long end;
	long long last;
};
node data[maxn];
bool compare(const node &a,const node &b)
{
	return a.end<b.end;
}
int main()
{
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%lld%lld",&data[i].last,&data[i].end);
	sort(data+1,data+1+n,compare);//排序 
	int ans=0;
	long long now=0;
	for(int i=1;i<=n;i++)
	{
		if(now<=data[i].end-data[i].last)//若当前时间 小于最晚开始时间 
		{
			now+=data[i].last;//累加,因为是要马不停蹄的干吗 
			q.push(data[i].last);//然后放入 
			ans+=1;//只有在直接往后排是答案才可以增加,其余时间都是在替换 
		}
		else
		{
			int nxt=q.top();//然后取出来一个当前完成任务中所需时间最大的任务 
			if(nxt>data[i].last&&now-nxt+data[i].last<=data[i].end)//比较 
			{//nxt>data[i].last是now-nxt+data[i].last<now然后移项后得到的
			// now-nxt+data[i].last<=data[i].end是说在如此更爱后可以完成本次操作 
				q.pop();//删除堆顶 
				now=now-nxt+data[i].last;//更变时间 
				q.push(data[i].last);//放入 
			}
		}
	}
	printf("%d",ans);//输出答案 
	return 0;
}

今天做完这两道带反悔操作的堆的贪心题后。

突然有一点小感触。

对于反悔操作,我们都是要找出他的逆操作来。然后我们还需要考虑什么时候使用逆操作。

然后我们一定要定序,只有定了序。我们才能按照一定的顺序贪心。这样的好处是,当你在扫描时,我们就可以使用一些数据结构来维护最值。而且在扫过的数据,你都可以拿来使用。

还有一定要从最基础的两个数据进行比较时分析。

posted @ 2018-07-11 15:43  Lance1ot  阅读(170)  评论(0编辑  收藏  举报