zoukankan      html  css  js  c++  java
  • 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;
    }
    

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

    突然有一点小感触。

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

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

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

  • 相关阅读:
    libTIFF 图像读取与保存
    MarkDown写作之嵌入LaTeX和HTML
    R语言学习(一)前言
    Multi-Byte Character Set & Unicode Character Set
    C/C++ ShellExecuteEx调用exe可执行文件
    C/C++中相对路径与绝对路径以及斜杠与反斜杠的区别
    观察者模式
    责任链模式
    桥接模式
    void及void指针含义的深刻解析
  • 原文地址:https://www.cnblogs.com/Lance1ot/p/9294859.html
Copyright © 2011-2022 走看看