• 51NOD贪心教程(任务执行顺序典型题+详细解析)


    有N个任务需要执行,第i个任务计算时占R[i]个空间,而后会释放一部分,最后储存计算结果需要占据O[i]个空间(O[i] < R[i])。

    例如:执行需要5个空间,最后储存需要2个空间。

    给出N个任务执行和存储所需的空间,问执行所有任务最少需要多少空间。

    分析: 本题可以抽象成,从一个整数开始,每次减去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 <cstring>
    #include <cstdio>
    #include <algorithm>
    
    using namespace std;
    
    const int MAXN = 1e5+10;
    
    struct D{
    	int R,O,flag;
    	bool operator < (const struct D &b)const {
    		return flag > b.flag;
    	}
    }board[MAXN];
    
    int main(){
    	
    	int N;
    	while(scanf("%d",&N) == 1){
    		for(int i=1 ; i<=N ; ++i){
    			scanf("%d %d",&board[i].R,&board[i].O);
    			board[i].flag = board[i].R - board[i].O;
    		}
    		sort(board+1,board+1+N);
    		int ma = 0,sum = 0,t = 0;
    		for(int i=1 ; i<=N ; ++i){
    			t = sum + board[i].R;
    			if(t > ma)ma = t;
    			sum += board[i].O;
    		}
    		printf("%d
    ",ma);
    	}
    	
    	return 0;
    }
    
    
  • 相关阅读:
    html禁止手机页面放大缩小
    <httpProtocol/>配置http协议头
    C# 并行编程 之 并发集合 (.Net Framework 4.0)(转)
    JavaScript随机排序算法1
    用户消息处理方式
    后台单用户在线,简单处理
    使用 Intel HAXM 为 Android 模拟器加速,媲美真机(转)
    解决Android SDK Manager下载太慢问题(转)
    如何正确并完全安装Visual Studio 2015企业版本?(转)
    C# XML流操作简单实例
  • 原文地址:https://www.cnblogs.com/vocaloid01/p/9514042.html
Copyright © 2020-2023  润新知