【BZOJ1029】[JSOI2007] 建筑抢修(堆优化贪心)

点此看题面
大致题意: 有N个受到严重损伤的建筑,对于每个建筑,修好它需要(T1)秒,且必须在(T2)秒之前修完((T1)(T2)不是固定值),问你最多能修好几个建筑。

题解

一看到这题,就能想到一个贪心的做法。

但是,裸贪心显然是不能过的,如果加上一个堆优化,就能够水过此题。

我们可以把修好每个建筑所需的时间放入大根堆中存储。对于每一个建筑,若能在规定时间内修好,则将(ans)(1),否则比较修好它所需的时间与堆顶元素的大小,若修好它所需的时间更少,则用其替换堆顶,此时(ans)不变。

代码

#include<bits/stdc++.h>
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define N 150000
using namespace std;
int n;
struct Building
{
	int a,t;
}s[N+5];
priority_queue<int> h;
inline char tc()
{
	static char ff[100000],*A=ff,*B=ff;
	return A==B&&(B=(A=ff)+fread(ff,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(int &x)
{
	x=0;char ch;
	while(!isdigit(ch=tc()));
	while(x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc()));
}
inline void write(int x)
{
	if(x>9) write(x/10);
	putchar(x%10+'0');
}
bool cmp(Building x,Building y)
{
	return x.t<y.t;
}
int main()
{
	register int i;
	for(read(n),i=1;i<=n;++i) read(s[i].a),read(s[i].t);
	sort(s+1,s+n+1,cmp);//将每一个建筑按无法重修的时间从小到大排序
	int tot=0,ans=0;//tot表示当前时间
	for(i=1;i<=n;++i)
	{
		if(s[i].t<tot+s[i].a)//判断时间是否来得及
		{
			if(s[i].a<h.top()) tot-=h.top(),h.pop(),h.push(s[i].a),tot+=s[i].a;//如果来不及,比较其与堆顶元素的大小,若其更小,则弹出堆顶,更新当前时间,并将修好该建筑所需时间加入堆中
		}
		else h.push(s[i].a),tot+=s[i].a,++ans;//如果来得及,ans加1,并将修好该建筑所需时间加入堆中
	}
	return write(ans),0;
}
原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ1029.html