递归的贪心和分治

贪心法求解会场安排问题

在这里插入图片描述
算法设计:
①分配的最终目的是要实现召开会议数目的最大化
②每个会议有固定的时间段召开,且同一时刻只有一个会议可以召开
在解决问题时思考最有效的贪心策略,若存在开始最早而持续时间长的会议或进行时间短但开始时间晚的会议都会损耗开销,综合考虑各种情况,既不能选择开始晚而进行时间短的会议,也不能选择开始最早而进行时间长的会议,最好的解决策略是在剩下的会议中选择具有最早结束时间且不会与其他已安排的会议重叠的会议来安排,这样可以使下一个会议尽早开始。
算法策略:使用递归的贪心算法解决此问题,使规定时间内召开的会议次数最大
数据结构:使用自定义的会议结构体和list列表完成

Begin
1 输入n(待安排会议个数)
输入fin(时间段长)
for i in range(0,n)
输入e.id(会议编号),e.start(开始时间),e.end(结束时间)
list.append(e)
2 将会议列表按照结束时间由小到大排序
3 now=0,list=[] //初始化当前时间和会议列表
4 if now<=fin:
		 i=0
While i<list.length do  //去掉开始时间大于当前时间的会议,得到相容会议列表
If list[i].start<now
remove list[i]
end
if list.length>0:	//确定选择列表首个会议,输出后删除列表首个会议
now=list[0].end  //更改当前时间为会议结束时间
print list[0]
remove list[0]
repeat 4   //递归解决
else return
end
# -*- coding: utf-8 -*-
class meeting:
    id=''
    start=0
    end=0
    
    
def sortkey(elem):
    return elem.end

def solve(t,fin,list):
    if(t<=fin):
        i=0
        while i < len(list):
            if list[i].start<t:
                list.pop(i)
                i -= 1
            i += 1

        if len(list)>0:
            t=list[0].end 
            print("  "+list[0].id+"   "+str(list[0].start)+"   "+str(list[0].end))
            
            list=list[1:]
            solve(t,fin,list)
        else:
            return
    

if __name__ == "__main__":
    n=input("请输入会议集合数目:")
    n=int(n)
    list=[]
    now=0
    fin=input("请输入时长:")
    fin=int(fin)
    i=0
    
    for i in range (0,n):
        e=meeting()
        e.id=input("请输入第"+str(i+1)+"个会议的id:")
        e.start=input("请输入第"+str(i+1)+"个会议的开始时间:")
        e.start=int(e.start)
        e.end=input("请输入第"+str(i+1)+"个会议的结束时间:")
        e.end=int(e.end)
        list.append(e)
        
    list.sort(key=sortkey)
    print("编号 开始 结束")
    solve(now,fin,list)

基于分治法的循环日程表

在这里插入图片描述
在这里插入图片描述

1 输入运动员个数n
2 map[n][n]=0
3 solve(n,map):
    if n=1:
        map[0][0]=1   return
    solve(n/2,map[0:len(map)/2,0:len(map)/2]) //repeat 3
    for i from len(map)/2) to len(map):
        for j in from 0 to len(map)/2:
            map[j][i]=m[j][i-len(map)/2]+len(map)/2 //右上角加len(map)/2 
            map[i][j]=m[i-len(map)/2][j]+len(map)/2 //左下角加len(map)/2 
            map[i][j+len(map)/2]=map[i-len(map)/2][j] //右下角复制

在我们得到的规律的基础上,采用分治法解决问题确保不出现重复的错误结果。

  • 分解:将问题分为若干个子问题。即将原日程表四分,研究n/2个运动员的情况
  • 解决:递归地求解每个子问题,直到子问题小到可以直接求解。将问题分解为一个运动员时得到结果,返回处理。
  • 合并:将每个子问题的解合并成为整个问题的解。左上角部分可以通过复制换算得到其他三部分日程表的数据,进行合并
# -*- coding: utf-8 -*-
import numpy as np

def solve(n,m):
    if n==1:
        m[0][0]=1
        return
    solve(int(n/2),m[0:int(len(m)/2),0:int(len(m)/2)])
    for i in range(int(len(m)/2),len(m)):
        for j in range(0,int(len(m)/2)):
            m[j][i]=m[j][i-int(len(m)/2)]+int(len(m)/2)
            m[i][j]=m[i-int(len(m)/2)][j]+int(len(m)/2)
            m[i][j+int(len(m)/2)]=m[i-int(len(m)/2)][j]
    
    

if __name__ == "__main__":
    n=input("请输入运动员数目:")
    n=int(n)
    
    map = np.zeros((n,n))
    print("队员  ",end="")
    for i in range(1,n):
        print(str(i)+"  ",end="")
    print()
    solve(n,map)
    print(map)

贪心算法是指:在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,所做出的仅是在某种意义上的局部最优解。贪心算法没有固定的算法框架,算法设计的关键是贪心策略的选择,贪心策略使用的前提是局部最优能导致全局最优。 贪心算法不是对所有问题都能得到整体最优解,选择的贪心策略必须具备无后效性,即某个状态以后的过程不会影响以前的状态,只与当前状态有关。所以对所采用的贪心策略一定要仔细分析其是否满足无后效性。
贪心算法每一步必须满足一下条件:
1、可行的:即它必须满足问题的约束。
2、局部最优:他是当前步骤中所有可行选择中最佳的局部选择。
3、不可取消:即选择一旦做出,在算法的后面步骤就不可改变了。
贪心算法的基本思路:
1、建立数学模型来描述问题。
2、把求解的问题分成若干个子问题。
3、对每一子问题求解,得到子问题的局部最优解。
4、把子问题的解局部最优解合成原来解问题的一个解。


分治法的设计思想是:将一个难以直接解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之。
分治策略是:对于一个规模为n的问题,若该问题可以容易地解决(比如说规模n较小)则直接解决,否则将其分解为k个规模较小的子问题,这些子问题互相独立且与原问题形式相同,递归地解这些子问题,然后将各子问题的解合并得到原问题的解。这种算法设计策略叫做分治法。
分治法所能解决的问题一般具有以下几个特征:
1、该问题的规模缩小到一定的程度就可以容易地解决
2、该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质。
3、利用该问题分解出的子问题的解可以合并为该问题的解;
4、该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子子问题。

分治法在每一层递归上都有三个步骤:
1、分解:将原问题分解为若干个规模较小,相互独立,与原问题形式相同的子问题;
2、解决:若子问题规模较小而容易被解决则直接解,否则递归地解各个子问题
3、合并:将各个子问题的解合并为原问题的解。

贪心算法和分治法都可以用递归来处理,这与两种算法的策略有关,由分治法产生的子问题往往是原问题的较小模式,这就为使用递归技术提供了方便。在这种情况下,反复应用分治手段,可以使子问题与原问题类型一致而其规模却不断缩小,最终使子问题缩小到很容易直接求出其解。这自然导致递归过程的产生。在本次试验中贪心算法使用动态规划的思想,且选择一旦做出,在算法的后面步骤就不可改变,他的每一个子问题的解决都可以套用递归的方法求解得到。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值