分析: 本題可以抽象成,從一個整數開始,每次減去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
不同語言如何處理輸入輸出,請查看下面的語言說明。
#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;
}