51nod 1099:任務執行順序 貪心

分析: 本題可以抽象成,從一個整數開始,每次減去a,再加上b (a,b都是正數),要求每次操作都不產生負數。


針對本題a[i] = R[i], b[i] = R[i] – O[i],注意O[i] < R[i],我們有0<b[i]<a[i]。 所以儘管每次有減有加,但是加的沒有減的多,總數還是在不斷見效的。關鍵我們是要“最有利”的一種執行順序。大家可以嘗試多種貪心策略。


我們給出標準答案——按照b[i]不增的順序排序,是最“有利”的。


爲了定義“有利”,我們這樣證明我們的結論:


如果對於b[0]>=b[1] >=…>=b[x] < b[x + 1] 
(a[0],b[0])….(a[x], b[x]) (a[x + 1], b[x + 1])的組合可以不產生負數,則我們交換b[x]和b[x + 1]也可以不產生負數。


證明:

交換(a[x], b[x])和(a[x + 1], b[x + 1])對x + 1更有利了,因爲每個括號實際上是一個負數,所以越早安排這個括號,被減數就越大,就越不容易形成負數。
關鍵看(a[x],b[x])移動到後面會不會產生負數。


那其實是看之前的結果 -a[x + 1] + b[x + 1] – a[x]會不會產生負數,(注意-a[x + 1] + b[x + 1]不會產生負數,因爲我們剛纔已經證明了,對x + 1更有利)


而我們知道之前的結果-a[x] + b[x] – a[x + 1]不會產生負數(因爲我們的假設就是這樣),而b[x + 1] > b[x],所以前者更大,所以-a[x + 1] + b[x + 1] – a[x]不會產生負數。

因此我們證明了交換之後仍然不產生負數,也就是原先不產生負數,我們交換後仍然不產生負數。

而經過若干次這樣的交換之後,我們肯定會把序列交換成按照b的不增順序排序的。從而我們證明了,任何可行的方案都不好於按照b不增順序排序的序列執行的方案,從而證明了我們的貪心策略是有效的。

很奇怪的策略——我們只考慮了b,居然能得到最優策略。可見貪心算法還是需要感覺,大膽假設,小心求證。

最後,我們來提供輸入輸出數據,由你來寫一段程序,實現這個算法,只有寫出了正確的程序,才能繼續後面的課程。

輸入

第1行:1個數N,表示任務的數量。(2 <= N <= 100000)
第2 - N + 1行:每行2個數R[i]和O[i],分別爲執行所需的空間和存儲所需的空間。(1 <= O[i] < R[i] <= 10000)

輸出

輸出執行所有任務所需要的最少空間。

輸入示例

20
14 1
2 1
11 3
20 4
7 5
6 5
20 7
19 8
9 4
20 10
18 11
12 6
13 12
14 9
15 2
16 15
17 15
19 13
20 2
20 1

輸出示例

135

請選取你熟悉的語言,並在下面的代碼框中完成你的程序,注意數據範圍,最終結果會造成Int32溢出,這樣會輸出錯誤的答案。

不同語言如何處理輸入輸出,請查看下面的語言說明。

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cmath>

using namespace std;

struct node{
int run;
int save;
}p[100001];

bool cmp(node n1,node n2)
{
    if(n1.run-n1.save!=n2.run-n2.save)
    {
        return n1.run-n1.save > n2.run-n2.save;
    }
    else
        return n1.run>=n2.run;
}

int main()
{
  int n;
  while(cin>>n){
    int sum=0;
    for(int i = 0;i < n ;i++){
        cin>>p[i].run>>p[i].save;
    }
    sort(p,p+n,cmp);

   int temp=0;
   for(int i = 0 ;i <n ;i++){
        sum+=p[i].run;
        temp=max(sum,temp);
        sum+=p[i].save;
        sum-=p[i].run;
   }
   cout<<temp<<endl;
}
 return 0;
}

網上的一種算法

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cmath>

using namespace std;

struct node{
int run;
int save;
}p[100001];

bool cmp(node n1,node n2)
{
    if(n1.run-n1.save!=n2.run-n2.save)
    {
        return n1.run-n1.save > n2.run-n2.save;
    }
    else
        return n1.run>=n2.run;
}

int main()
{
  int n;
  while(cin>>n){
    int sum=0;
    for(int i = 0;i < n ;i++){
        cin>>p[i].run>>p[i].save;
        sum+=p[i].save;
    }
    sort(p,p+n,cmp);

   int already = 0;
   int temp;
   for(int i = 0; i< n ; i++){
       temp = already + p[i].run;
       already = already + p[i].save;
       sum = max(sum,temp);
   }
   cout<<sum<<endl;
  }
  return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章