题目描述 Description
小刚在玩JSOI提供的一个称之为“建筑抢修”的电脑游戏: 经过了一场激烈的战斗,T部落消灭了所有z部落的入侵者。但是T部落的基地里已经有N个建筑设施受到了严重的损伤,如果不尽快修复的话,这些建筑设施将会完全毁坏。现在的情况是:T部落基地里只有一个修理工人,虽然他能瞬间到达任何一个建筑,但是修复每个建筑都需要一定的时间。同时,修理工人修理完一个建筑才能修理下一个建筑,不能同时修理多个建筑。如果某个建筑在一段时间之内没有完全修理完毕,这个建筑就报废了。你的任务是帮小刚合理的制订一个修理顺序,以抢修尽可能多的建筑。
输入描述 Input Description
第一行是一个整数N,接下来N行每行两个整数T1,T2描述一个建筑:修理这个建筑需要T1秒,如果在T2秒之内还没有修理完成,这个建筑就报废了。
输出描述 Output Description
输出一个整数S,表示最多可以抢修S个建筑。
样例输入 Sample Input
4
100 200
200 1300
1000 1250
2000 3200
样例输出 Sample Output
3
数据范围及提示 Data Size & Hint
N<150000,t<=15000
【2017.10.16考试T1】
贪心。
考试时的贪心思路:分别按照T1和T2进行排序,对排序后的结果分别进行处理,能计入答案就计入答案,不能计入答案就看下一个。对两种结果取最大值。
策略有漏洞。如若先将t1=8,t2=18计入答案,再来一个t1=6,t2=20将超出答案的话,此时应当将前者取出放入后者才更优,而我的贪心策略没有这个过程,于是gg。
正解:
先按照T2排序,T2相同的按照T1排序。
建立一个大根堆,堆顶是所需时间最多的建筑。
从第一个建筑开始,如果当前建筑所需时间+抢修之前建筑所需时间<=当前T2,则将当前建筑放入堆里,更新总时间,ans++。
如果不满足上述条件,则将当前建筑所需时间与堆顶元素进行比较。若当前T1<堆顶T1,则弹出堆顶元素,将当前元素放入堆顶,更新总时间。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=200000+2;
int n,ans;
struct node
{
int a,b;
}s[maxn];
/*bool cmp(node x,node y)
{
return x.b<y.b;
}*/
bool cmp(node x,node y)
{
return x.b==y.b?x.a<y.a:x.b<y.b;
}
priority_queue<node>q;
bool operator < (node a,node b)
{
return a.a<b.a;
}
int main()
{
int tot=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&s[i].a,&s[i].b);
}
sort(s+1,s+n+1,cmp);//按照截稿时间先后排序
for(int i=1;i<=n;i++)
{
if(s[i].a+tot<=s[i].b)
{
q.push(s[i]);
ans++;
tot+=s[i].a;
}
else
{
node t=q.top();
if(s[i].a>t.a) continue;
else
{
q.pop();
tot-=t.a;
q.push(s[i]);
tot+=s[i].a;
}
}
}
printf("%d",ans);
return 0;
}
好题好题。
以后,,应当考虑全面才是,思路经常不对就是自己的问题了。而且要联想到一些基本的数据结构,栈队列堆虽然没什么技术含量但常常成为解题的关键。