【算法学习笔记07】贪心算法(Greedy Algorithm)

 

目录

1 什么是贪心算法

2 贪心算法的基本步骤

3 贪心算法的基本框架

4 贪心策略的选择和算法的缺陷

5 实例--进程调度问题


在学习之前可以看一个非常著名的问题:

旅行推销员问题是这样一个问题:给定一系列城市和每对城市之间的距离,求解访问每一座城市一次并回到起始城市的最短回路。

解决方法之一

最近邻点法:一开始以寻找离起始站最近的需求点为起始路线的第一个城市,此后寻找离最后加入路线的顾客最近的需求点,直到最后。

这个最近邻点法就是一个很典型用贪心算法的思想来解决问题的方法。

1 什么是贪心算法

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

总而言之,贪心算法就是将求解过程分成若干个步骤,每个步骤都应用贪心策略,选取当前状态下最优的选择,并希望最后堆叠出的结果也是最优解。

       

 

2 贪心算法的基本步骤

  1. 创建一个数学模型来描述问题
  2. 把求解的问题分成若干个子问题
  3. 采用迭代的过程,对每一个子问题求解,得到子问题的局部最优解
  4. 把子问题的解局部最优解合成原来解问题的一个解。

        以开头提出的旅行推销员的问题的最近邻点解决方案为例子:

        1.数学模型:一个城市可以看作一个节点,则多个城市一起组合成了一个无向图,要寻找遍历完所有节点的最短路径。

        2.分成若干个子问题:从一个节点到另一个节点可以看作是一个子问题。

        3.迭代解决子问题: 从第一个起始点开始找到离起始点最近的节点,再从这个节点找到最近的节点,.....以此类推。

        4.合成为整体问题的解:以此类推,最后得到整体问题的解决方案

3 贪心算法的基本框架

从问题的初始解出发:

while(还没有结束解决所有子问题):

{

        利用当个子问题的解决办法

}

将所有问题进行结合成一个最终解

 

4 贪心策略的选择和算法的缺陷

贪心策略的选择:因为贪心算法是通过局部子问题的最优解决方案来得出全局最优解,所以这个时候贪心策略的选择就变得格外重要,局部最优的累积也是全局最优,这是贪心算法的关键。 

贪心算法的缺陷:由于贪心算法我们比较关注局部的最优解,所有贪心算法使用的前提就是,局部最优迭代可以得到全局最优。并且这对贪心策略的选择要求比较高。

5 实例--进程调度问题

有n个进程要执行,每个进程有开始时间Si秒和结束时间Ti秒,同一时间只能执行一个进程。
问如何调度进程,使得在时间m内尽可能多的完成进程。

如果我们采用贪心算法来解决这个问题,我们会经过以下几个过程:

        1.数学模型:一个进程可以看作一段时间,问题变成了如何在m长度的时间内,安排最多的进程时间段。

        2.分成若干个子问题:从起始点,应该调度哪一个进程,该进程结束又该调度哪一个进程。

        3.迭代解决子问题: 选择一个贪心策略,重复该策略,直到时间m结束。

        4.合成为整体问题的解:以此类推,最后得到整体问题的解决方案。

那么如何选择贪心策略呢?每次都选择,最先开始的进程?执行时间最短的进程?最先结束的进程?

事实上,每次选择最早结束的进程的效果会达到最佳。所以我们的贪心策略是,每次都选择最先结束的进程进行调度。

我们的代码实现的框架是什么呢?

从0时刻出发:

while(time<m):

{

        从还未调度的进程中选择最早结束的进程进行调度。

        time=time+调度的进程的时间

}

得到输出调度的顺序

代码实现: 

#将进程封装成类
class task:
    def __init__(self,name:str,start:int,end:int):
        self.name=name
        self.start=start
        self.end=end
        self.time=end-start

#删除已经过了开始时间的
def delete_task(start_time,list:list):
    delete=[]
    for i in list:
        if start_time>i.start:
            delete.append(i)
    for i in delete:
        list.remove(i)
    return list

#找到最先结束的
def find_max(list):
    min=task("",0,10000)
    for i in list:
        if min.end>i.end:
            min=i
    return min

#贪心算法调度
def task_dispatch(task_list:list,end_time:int):
    start_time=0
    res=[]
    while(start_time<=end_time):
        dispatch=find_max(task_list)#找到当前最小的
        res.append(dispatch)
        start_time=dispatch.end
        task_list=delete_task(start_time,task_list)#删除已经不能执行的进程
    return res

运行测试:

task1=task("1",2,9)
task2=task("2",4,7)
task3=task("3",6,7)
task4=task("4",3,5)
task5=task("5",7,8)

task_list=[task1,task2,task3,task4,task5]
res=task_dispatch(task_list,10)
for i in res:
    print(i.name)

结果:

测试成功! 

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值