Greedy:Cow Acrobats(POJ 3045)
题目大意:一群牛想逃跑,他们想通过搭牛梯来通过,现在定义risk(注意可是负的)为当前牛上面的牛的总重量-当前牛的strength,问应该怎么排列才能使risk最小?
说实话这道题我一开始给书上的二分法给弄懵了,后来看了一下题解发现根本不是这么一回事,其实就是个简单的贪心法而已。
这题怎么贪心呢?就是按w+s从小到大排序就好了,证明一下:
1.先证明如果不满足w+s的序列性,无论谁在谁的上面,都会违反题设:(设A在B的上面)
如果 A.s+A.w<B.s+B.w
则如果B.s<m+A.w
则如果B在A的上面A.s<B.s+B.w-A.w=B.w+m
得证
2.再证明一下如果采用排序的确能让risk的最大值最小。
如果 A.s+A.w<B.s+B.w
①A在B的上面
riskA1=m-A.s riskB1=m+A.w-B.s
②B在A的上面
riskB2=m-B.s riskA2=m+B.w-A.s
所以riskA2>riskA1
另外riskB1-riskA2=A.w+A.s-B.w-B.s<0 所以riskA2>riskB1>riskB2
则违反后risk会产生一个比三个risk更大的数,不符合题意
参考http://poj.org/showmessage?message_id=341726
1 #include <iostream> 2 #include <algorithm> 3 #include <functional> 4 5 using namespace std; 6 typedef long long LL_INT; 7 8 typedef struct _cows 9 { 10 LL_INT strength; 11 LL_INT weight; 12 bool operator<(const _cows &x) const 13 { 14 return strength + weight > x.weight + x.strength; 15 } 16 }Cows; 17 18 static Cows cows_set[50001]; 19 void Search(const int, LL_INT); 20 bool judge(const LL_INT, const int,const LL_INT); 21 22 int main(void) 23 { 24 int sum_cows; 25 LL_INT sum_w; 26 27 while (~scanf("%d", &sum_cows)) 28 { 29 sum_w = 0; 30 for (int i = 0; i < sum_cows; i++) 31 { 32 scanf("%lld%lld", &cows_set[i].weight, &cows_set[i].strength); 33 sum_w += cows_set[i].weight; 34 } 35 sort(cows_set, cows_set + sum_cows); 36 Search(sum_cows,sum_w); 37 } 38 return 0; 39 } 40 41 void Search(const int sum_cows, LL_INT sum_w) 42 { 43 LL_INT ans = -1000000001; 44 45 for (int i = 0; i < sum_cows; i++) 46 { 47 sum_w -= cows_set[i].weight; 48 ans = max(ans, sum_w - cows_set[i].strength); 49 } 50 cout << ans << endl; 51 }
其实这题的思想和Protecting Flowers那题有点像,都是只看两个元素之间的两个量之间的练联系,而不只是单单的一个量