入门贪心算法

贪心算法必知的知识点

贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。

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


基本思路

建立数学模型来描述问题;

把求解的问题分成若干个子问题;

对每一子问题求解,得到子问题的局部最优解;

把子问题的解局部最优解合成原来解问题的一个解。


案例分析

区间调度问题(interval shecduling)

问题描述:

这是《算法导论》上的例子,也是一个非常经典的问题。有n个需要在同一天使用同一个教室的活动a1,a2,…,an,教室同一时刻只能由一个活动使用。每个活动ai都有一个开始时间si和结束时间fi 。一旦被选择后,活动ai就占据半开时间区间[si,fi)。如果[si,fi]和[sj,fj]互不重叠,ai和aj两个活动就可以被安排在这一天。该问题就是要安排这些活动使得尽量多的活动能不冲突的举行。例如下图所示的活动集合S,其中各项活动按照结束时间单调递增排序。


几种贪心策略:

1.最早开始时间  

即用每个工作的开始时间进行升序排列,在保证不冲突的情况下,每次选择开始时间最小的情况。

2.最早结束时间

即用每个工作的结束时间进行升序排列,在保证不冲突的情况下(仍然考虑下一次的结束时间尽可能的小,且下一次的开始时间需要大于上一次的结束时间),每次选择结束时间最小的情况。(上图)

3.最少的运行时间

即每一个工作的结束时间减去开始时间得到运行时间,并且在不冲突的情况下,每次选择运行时间最短的工作。

4.最少冲突情况

即首先计算出当前的工作i,它的冲突个数为k[i],用k[i]进行上升排序。每次选择冲突最小的情况。

哪种策略下能得到最优解?答:最早结束时间

 证明方法:构造法(深灰表选中的工作,浅灰表示反例)

最早开始时间:假设最早开始时间的工作的运行时间很长,就不是最优。

最少运行时间:假设最少运行时间的的那个工作的结束时间很晚,就不是最优。

最少冲突:按上图的情况,首先会选到深灰,然后再选择旁边的浅灰,总共只有三个工作被选中,不是最优。

接着证明最早结束时间是最优的(可以用归纳法)

算法思想:

            1.先按完成时间上升排序

            2.选择当前的结束时间的最早的工作,判断该工作的开始时间是否满足大于上一个工作的结束时间

            3.如果不满足,则寻找下一个,满足的话重复2步,就选择,直到遍历完

总结而言就是:先排序,不冲突就选择加入A(被选择的job),冲突就丢弃并遍历下一个,最后返回A

实现:https://www.jianshu.com/p/89f8c67b2a04

钱币找零问题

问题描述:这个问题在我们的日常生活中就更加普遍了。假设1元、2元、5元、10元、20元、50元、100元的纸币分别有c0, c1, c2, c3, c4, c5, c6张。现在要用这些钱来支付K元,至少要用多少张纸币?用贪心算法的思想,很显然,每一步尽可能用面值大的纸币即可。在日常生活中我们自然而然也是这么做的。

贪心策略:

最大面值:在程序中已经事先将Value按照从大到小的顺序排好。

算法思想:1.首先将面值从大到小排序 2.计算K/V的取低值为n,记录n,并求得剩余的K,重复2过程,直到K的取值为零。

背包问题

问题描述:有一个背包,背包容量是M=150。有7个物品,物品可以分割成任意大小。要求尽可能让装入背包中的物品总价值V最大,但不能超过总容量M。


贪心策略:

最大价值:在保证不超重的情况下,每次选择价值最大的物品。

结果:DBFE  不是最优

最小容量:在保证不超重的情况下,每次选择重量最小的物品。

结果:FGBAE  不是最优

最大单位容量的价值:选择单位容量下,价值最大的那一个。

结果:FBGD   40+40+30+50

算法思想:

1.按单位容量的价值由大到小排序

2.如果不超重,就选择,超重就舍弃。

实现:https://www.jianshu.com/p/50f1d4e0555c

最小生成树问题

问题描述:

求一个连通无向图的最小生成树的代价(图边权值为正整数)。

Kruskal算法简述

假设 WN=(V,{E}) 是一个含有 n 个顶点的连通网,则按照克鲁斯卡尔算法构造最小生成树的过程为:先构造一个只含 n 个顶点,而边集为空的子图,若将该子图中各个顶点看成是各棵树上的根结点,则它是一个含有 n 棵树的一个森林。之后,从网的边集 E 中选取一条权值最小的边,若该条边的两个顶点分属不同的树,则将其加入子图,也就是说,将这两个顶点分别所在的两棵树合成一棵树;反之,若该条边的两个顶点已落在同一棵树上,则不可取,而应该取下一条权值最小的边再试之。依次类推,直至森林中只有一棵树,也即子图中含有 n-1条边为止。

模拟过程:https://www.jianshu.com/p/50f1d4e0555c

算法难点:

(1)边的选择要求从小到大选择,则开始显然要对边进行升序排序。

(2)选择的边是否需要,则从判断该边加入后是否构成环入手。

算法设计:

(1)对边升序排序

在此采用链式结构,通过插入排序完成。每一结点存放一条边的左右端点序号、权值及后继结点指针

(2)边的加入是否构成环

一开始假定各顶点分别为一组,其组号为端点序号。选择某边后,看其两个端点是否在同一组中,即所在组号是否相同,如果是,表示构成了环,则舍去。  如果两个端点所在的组不同,则表示可以加入,则将该边两端的组合并成同一组。

参考:https://www.jianshu.com/p/50f1d4e0555c

你可能感兴趣的:(入门贪心算法)