基本算法之贪心算法

看了刘汝佳大牛的黑书果然很有体会,虽然很难,但是真的题题经典,一定要坚持坐下去,下面我们来说说贪心法

贪心算法即是每次选择局部最优策略进行实施,而不去考虑对今后的影响。贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。

下面来看一个题目:

POJ1042 钓鱼(黑书)

链接:http://poj.org/problem?id=1042

贪心:为了不讨论在路上花费的时间,可以枚举到过的湖:比如:a=j 表示到过湖1、2、..、j相应的, 花在路上的时间
* 就是 t[1]+t[2]+..+t[j-1] (显然每段路只会走一次) 于是算出time,表示花在钓鱼上的时间,往回走并没有好处,因此我们不选择往回走
*     这样一来,就不同再考虑路上的时间了,可以认为John有瞬间移动,哪个湖鱼多,就到哪个湖钓(当然 湖的编号 满足 1 <= ~ <=a)

我们依次枚举究竟要在前多少个湖钓鱼,那么我们可以先将路上的时间计算好,然后人为我们可以在这几个湖之间瞬间转移,每次挑一个上钩率最高的湖去钓即可。

代码参看的是金海峰大牛,同时学会了新的代码风格,以后将会沿用下去

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<string>
 5 #include<cmath>
 6 #include<cctype>
 7 #include<algorithm>
 8 #include<vector>
 9 #include<map>
10 #include<stack>
11 using namespace std;
12 const int maxn=30;
13 int f[maxn],d[maxn],t[maxn],ans[maxn];
14 int n,h,ansf;
15 bool p=false;
16
17 void init()  //输入部分,用函数更好
18 {
19     cin>>h;
20     h*=12;
21     ansf=-1;
22     for(int i=1;i<=n;i++)
23         cin>>f[i];
24     for(int i=1;i<=n;i++)
25         cin>>d[i];
26     for(int i=1;i<n;i++)
27         cin>>t[i];
28 }
29
30 void make(int a,int time)
31 {
32     int ls[maxn],ans1[maxn],mx,mxi,fish=0;
33     memset(ans1,0,sizeof(ans1));
34     for(int i=1;i<=a;i++)
35         ls[i]=f[i];
36     while(time>0)  //此处开始用贪心法,求出最优方案
37     {
38         mx=-1;
39         mxi=-1;
40         for(int i=1;i<=a;i++)
41             if(mx<ls[i])
42         {
43             mx=ls[i];
44             mxi=i;
45         }
46         fish+=mx;
47         ans1[mxi]+=1;
48         ls[mxi]=0>ls[mxi]-d[mxi]?0:ls[mxi]-d[mxi];
49         time--;
50     }
51     if(fish<ansf)
52         return;
53     if(fish>ansf)
54     {
55         for(int i=1;i<=n;i++)
56             ans[i]=ans1[i];
57         ansf=fish;
58         return;
59     }
60     int j=1;
61     while(j<=n&&ans[j]==ans1[j])
62         j++;
63     if(ans1[j]>ans[j])
64         for(int i=1;i<=n;i++)
65         ans[i]=ans1[i];
66 }
67 void work()
68 {
69     int time=0;
70     t[0]=0;
71     for(int i=1;i<=n;i++)  //“瞬间转移”经典做法
72     {
73         time+=t[i-1];
74         make(i,h-time);
75     }
76 }
77
78 void print()  //输出部分,用函数更好
79 {
80     if(p)
81         cout<<endl;
82         for(int i=1;i<n;i++)
83             cout<<ans[i]*5<<", ";
84         cout<<ans[n]*5<<endl<<"Number of fish expected: "<<ansf<<endl;
85         p=true;
86 }
87 int main()
88 {
89     while(cin>>n)
90     {
91         if(n==0)
92             break;
93         init();
94         work();
95         print();
96     }
97     return 0;
98 }

时间: 2024-10-19 22:35:00

基本算法之贪心算法的相关文章

五大算法思想—贪心算法

贪心法理解 贪心法在解决问题的策略上目光短浅,只根据当前已有的信息就做出选择,而且一旦做出了选择,不管将来有什么结果,这个选择都不会改变.换言之,贪心法并不是从整体最优考虑,它所做出的选择只是在某种意义上的局部最优. 一句话:不求最优,只求可行解. 判断贪心法 对于一个具体的问题,怎么知道是否可用贪心算法解此问题,以及能否得到问题的最优解? 我们可以根据贪心法的2个重要的性质去证明:贪心选择性质和最优子结构性质. 1.贪心选择性质 什么叫贪心选择?从字义上就是贪心也就是目光短线,贪图眼前利益,在

算法导论--贪心算法与动态规划(活动选择问题)

活动选择问题 有一个教室,而当天有多个活动,活动时间表如下:找出最大兼容活动集!活动已按结束时间升序排序. 动态规划 采用动态规划需要满足两个条件:1.最优子结构2.子问题重叠 令Sij表示在ai结束后和aj开始前活动的集合,假定Aij为活动集合Sij的最大兼容子集,其中包含活动ak.问题变成求Sik与Skj最大兼容活动子集Aik与Akjz.我们用c[i,j]表示Sij的最优解的大小. 则c[i,j] = c[i,k]+c[k,j]+1;最后我们需要遍历所有可能的k值,找出最大的一个划分作为c[

五大常用算法之三贪心算法

贪心算法 贪心算法简介: 贪心算法是指:在每一步求解的步骤中,它要求"贪婪"的选择最佳操作,并希望通过一系列的最优选择,能够产生一个问题的(全局的)最优解. 贪心算法每一步必须满足一下条件: 1.可行的:即它必须满足问题的约束. 2.局部最优:他是当前步骤中所有可行选择中最佳的局部选择. 3.不可取消:即选择一旦做出,在算法的后面步骤就不可改变了. 贪心算法案例: 1.活动选择问题  这是<算法导论>上的例子,也是一个非常经典的问题.有n个需要在同一天使用同一个教室的活动a

算法导论----贪心算法,删除k个数,使剩下的数字最小

先贴问题: 1个n位正整数a,删去其中的k位,得到一个新的正整数b,设计一个贪心算法,对给定的a和k得到最小的b: 一.我的想法:先看例子:a=5476579228:去掉4位,则位数n=10,k=4,要求的最小数字b是n-k=6位的: 1.先找最高位的数,因为是6位数字,所以最高位不可能在后5位上取到(因为数字的相对顺序是不能改变的,假设如果取了后五位中倒数第5位的7,则所求的b就不可能是6位的了,最多也就是4位的79228)理解这点很重要!所以问题变成从第1位到第k+1(n-(n-k-1))取

[算法导论]贪心算法(greedy algorithm)

转载请注明出处:http://www.cnblogs.com/StartoverX/p/4611544.html 贪心算法在每一步都做出当时看起来最佳的选择.也就是说,它总是做出局部最优的选择,寄希望(证明)这样的选择能够导致全局最优解. 贪心算法和动态规划都依赖于最优子结构,也就是一个问题的最优解包含其子问题的最优解.不同的是,动态规划通常需要求解每一个子问题,通过对所有子问题的求解得到最终问题的解.而贪心算法寄希望于通过贪心选择来改进最优子结构,使得每次选择后只留下一个子问题,大大简化了问题

【经典算法】贪心算法

贪心算法分阶段工作.在每一个阶段,可以认为所做的决定是好的,而不考虑将来的后果.一般来说,这意味着选择的是某个局部最优.这种“眼下能够拿到的就拿”的策略是这类算法名称的来源.当算法终止时,我们希望局部最优就是全局最优.如果真是这样的话,那么算法就是正确的:否则,算法得到的是一个次最优解.如果不要求绝对的最佳答案,那么有时用简单的贪心算法生成近似答案,而不是使用一般来说产生准确答案所需要的复杂算法. 可以根据如下步骤来设计贪心算法: 1. 将优化问题转化成这样的一个问题,即像做出选择,再解决剩下的

简单理解算法篇--贪心算法

贪心算法是什么意思?举个例子就很清楚了:现在你有一个能装4斤苹果的袋子,苹果有两种,一种3斤一个,一种2斤一个,怎么装才能得到最多苹果?当然我们人考虑的话当然是拿两个2斤的苹果,就刚好装满了,但是如果按贪心算法拿的话,首先就要把最重的苹果拿下(是不是很符合贪心两个字?),但并没有得到最多苹果. 贪心算法保证了局部最优,但并不能保证得到最优解. 什么时候用贪心法?满足下面两个条件 1.       具有最优子结构 2.       贪心选择性 第1点跟动态规划的条件一样,其实贪心跟动态规划一样,都

回溯算法 和 贪心算法(全排列)

一:简介 (1)回溯法 又称试探法 回溯法的基本做法是深度优先搜索,是一种组织得井井有条的.能避免不必要重复搜索的穷举式搜索算法:基本思想是:从一条路往前走,能进则进,不能进则退回来,换一条路再试. 适用场景:当遇到某一类问题时,它的问题可以分解,但是又不能得出明确的动态规划或是递归解法,此时可以考虑用回溯法解决此类问题.回溯法的优点在于其程序结构明确,可读性强,易于理解,而且通过对问题的分析可以大大提高运行效率.但是,对于可以得出明显的递推公式迭代求解的问题,还是不要用回溯法,因为它花费的时间

算法专题——贪心算法

贪心算法正确性证明: 1.证明贪心选择性质:经过贪心选择,可以获得最优解 2.最优子结构:证明子问题最优解与贪心选择组合,结果依然是最优解 •All we really need to do is argue that an optimal solution to the subproblem, combined with the greedy choice already made, yields an optimal solution to the original problem. 例: