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;
}


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