bzoj1029 [JSOI2007]建筑抢修
1029: [JSOI2007]建筑抢修
Time Limit: 4 Sec Memory Limit: 162 MBSubmit: 2872 Solved: 1278
[Submit][Status][Discuss]
Description
小刚在玩JSOI提供的一个称之为“建筑抢修”的电脑游戏:经过了一场激烈的战斗,T部落消灭了所有z部落的入侵者。但是T部落的基地里已经有N个建筑设施受到了严重的损伤,如果不尽快修复的话,这些建筑设施将会完全毁坏。现在的情况是:T部落基地里只有一个修理工人,虽然他能瞬间到达任何一个建筑,但是修复每个建筑都需要一定的时间。同时,修理工人修理完一个建筑才能修理下一个建筑,不能同时修理多个建筑。如果某个建筑在一段时间之内没有完全修理完毕,这个建筑就报废了。你的任务是帮小刚合理的制订一个修理顺序,以抢修尽可能多的建筑。
Input
第一行是一个整数N,接下来N行每行两个整数T1,T2描述一个建筑:修理这个建筑需要T1秒,如果在T2秒之内还没有修理完成,这个建筑就报废了。
Output
输出一个整数S,表示最多可以抢修S个建筑.N < 150,000; T1 < T2 < maxlongint
Sample Input
100 200
200 1300
1000 1250
2000 3200
Sample Output
HINT
Source
题意:不多解释
分析:这是一道贪心
先按照终止时间排序
然后能加进去的就加进去
不能加进去的就判断下当前这个建筑的修复时间是否小于 在修缮队列里耗时最长的那一个,如果小于就替换它(因为这样答案不变,总时间变小),
否则不管这个建筑
为什么这个贪心是正确的,首先我们证明按终止时间排序是正确的
显然,如果最优答案的修缮顺序不是按照终止时间排序的,那么将其按照终止时间排序后并不影响这个修缮顺序的正确性
现在证明那个贪心策略的正确性
首先如果当前这个建筑存在与最优修缮序列里,而我们的贪心策略将其忽略,导致最优答案变少,那么我们就错误了(现在证明这种情况不可能)
好的,现在假设我们因为不加入而导致最优答案变少,即我们因为不加进这个建筑,导致后面某些最优序列里的建筑我们无法加入
好吧,那么我们加进这个建筑x,讨论所有情况
1、如果我们因此要剔除一个在序列里的建筑,那么显然是不可能的,因为按照贪心策略,这个建筑x无法加入序列,如果剔除一个建筑并把它加入,显然序列长度不变,但时间变长了
2、如果我们因此要剔除两个或以上在序列里的建筑,然后才可以加入后面最优序列里的那些建筑,并使序列长度比纯贪心序列的长度要长,那么也是不可能的,因为若它们不被贪心策略采纳,耗时肯定大于贪心序列里最大的一个,而那个建筑进入序列后,序列的长度变短,时间也一定变短(不然怎么可能更优!?),然而这个变短的长度绝不会大于等于原来贪心序列里最大的一个(不然为什么还要剔除多一个,就是说你剔除k个建筑就能装下建筑x,然而你剔除了k+1个),那么就是说我加入了这个建筑x,然而最优序列的后面的建筑我一个加不进去,T_T,这显然与加入这个建筑x使序列边长矛盾
所以不存在一种情况是加入这个贪心序列不加入的建筑x是更优的。。。。
所以贪心策略正确
废话好多,其实大家用暴力验证一下就好
下面是代码
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <deque> 6 #include <vector> 7 #include <queue> 8 #include <iostream> 9 #include <algorithm> 10 #include <map> 11 #include <set> 12 #include <ctime> 13 using namespace std; 14 typedef long long LL; 15 typedef double DB; 16 #define For(i, s, t) for(int i = (s); i <= (t); i++) 17 #define Ford(i, s, t) for(int i = (s); i >= (t); i--) 18 #define Rep(i, t) for(int i = (0); i < (t); i++) 19 #define Repn(i, t) for(int i = ((t)-1); i >= (0); i--) 20 #define rep(i, x, t) for(int i = (x); i < (t); i++) 21 #define MIT (2147483647) 22 #define INF (1000000001) 23 #define MLL (1000000000000000001LL) 24 #define sz(x) ((int) (x).size()) 25 #define clr(x, y) memset(x, y, sizeof(x)) 26 #define puf push_front 27 #define pub push_back 28 #define pof pop_front 29 #define pob pop_back 30 #define ft first 31 #define sd second 32 #define mk make_pair 33 inline void SetIO(string Name) { 34 string Input = Name+".in", 35 Output = Name+".out"; 36 freopen(Input.c_str(), "r", stdin), 37 freopen(Output.c_str(), "w", stdout); 38 } 39 40 const int N = 150010; 41 typedef pair<int, int> State; 42 State Building[N]; 43 priority_queue<int> List; 44 int n; 45 46 inline void Input() { 47 scanf("%d", &n); 48 For(i, 1, n) scanf("%d%d", &Building[i].sd, &Building[i].ft); 49 } 50 51 inline void Solve() { 52 sort(Building+1, Building+1+n); 53 54 LL Cnt = 0; 55 For(i, 1, n) { 56 int Cost = Building[i].sd; 57 if(Cost+Cnt <= Building[i].ft) Cnt += Cost, List.push(Cost); 58 else { 59 int x = List.top(); 60 if(x <= Cost) continue; 61 List.pop(); 62 List.push(Cost); 63 Cnt = Cnt-x+Cost; 64 } 65 } 66 67 printf("%d\n", sz(List)); 68 } 69 70 int main() { 71 #ifndef ONLINE_JUDGE 72 SetIO("1029"); 73 #endif 74 Input(); 75 Solve(); 76 return 0; 77 }