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那题有点像,都是只看两个元素之间的两个量之间的练联系,而不只是单单的一个量

原文地址:https://www.cnblogs.com/Philip-Tell-Truth/p/5132093.html