BZOJ1029 [JSOI2007]建筑抢修[贪心]
(贪心题的策略真的好迷啊,做了多少题还是不会做。。)
贪心策略成功被我第一时刻就想歪了。然后后面都是对的qwq,真的是。。
正解应当是将报废时间排序,显然对于维修每一个建筑进行结束的越早越好,从小到大排。然后按顺序看可不可以修。如果当前时间加上维修时间够的话就加入,不够就看之前有没有哪个建筑耗时比现在长的,有就将之替换为当下这个,显然更优。做完就行啦。
其实这个是基于一个结论,如果可以满足先修好一个报废时间靠后的建筑再能够修一个报废时间靠前的建筑,那一定交换维修顺序也可以(可以画线段图理解)。那么最优解一定存在一种按报废时间从小到大的顺序 的方案。这也就是我贪心的依据之一。本来我的思路按最迟开工时间(报废减去修理时间)排序,但是这样的话没办法保证最优解是开工时间从小到大的。。比如输入:
2
3 4
1 3
这个顺序就不对了呢。所以当开工时间不行时,应当转换思路,避免和调整弥补漏洞(上面这种数据),然而。。我没转换上来。我好逊啊。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 #include<queue> 7 #define dbg(x) cerr<<#x<<" = "<<x<<endl 8 #define ddbg(x,y) cerr<<#x<<" = "<<x<<" "<<#y<<" = "<<y<<endl 9 using namespace std; 10 typedef long long ll; 11 template<typename T>inline char MIN(T&A,T B){return A>B?A=B,1:0;} 12 template<typename T>inline char MAX(T&A,T B){return A<B?A=B,1:0;} 13 template<typename T>inline T _min(T A,T B){return A<B?A:B;} 14 template<typename T>inline T _max(T A,T B){return A>B?A:B;} 15 template<typename T>inline T read(T&x){ 16 x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1; 17 while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x; 18 } 19 const int N=200000+7; 20 struct WPH{ 21 int ed,tim; 22 inline bool operator <(const WPH&orz)const{ 23 return ed<orz.ed; 24 } 25 }a[N]; 26 priority_queue<int> q; 27 int n,tot,ans; 28 29 int main(){//freopen("test.in","r",stdin);//freopen("test.out","w",stdout); 30 read(n); 31 for(register int i=1;i<=n;++i)read(a[i].tim),read(a[i].ed); 32 sort(a+1,a+n+1); 33 for(register int i=1;i<=n;++i){ 34 if(tot+a[i].tim<=a[i].ed)tot+=a[i].tim,q.push(a[i].tim),++ans; 35 else if(q.top()>a[i].tim)tot-=q.top(),q.pop(),tot+=a[i].tim,q.push(a[i].tim); 36 } 37 printf("%d\n",ans); 38 return 0; 39 }