算法-贪心

p_G.png

在这里插入图片描述

k_G.png

在这里插入图片描述

n_G.png

在这里插入图片描述
代码里会用到。。

  • 活动安排问题
  • 非0-1揹包问题
  • 最优装载问题
  • 哈服满编码,最小生成树,单源最短路径

理论知识

一般可以通过对算法步数的归纳或通过对问题规模的归纳来证明贪心法的正确性。
证明贪心选择将导致整体的最优解:
首先证明存在问题的一个整体最优解必定包含了第一个贪心选择。
然后证明在做了贪心选择后,原问题简化为规模较小的类似子问题,即可继续使用贪心选择。
于是用数学归纳法可证明,经过一系列贪心选择可以得到整体最优解。

贪心法的证明
1.数学归纳法
1.1 根据算法步数
1.2 根据问题规模
2.反证法

活动安排问题的证明

证明:(对算法步数进行归纳)
(1)将活动集合按照截止时间递增顺序排列,得到序列S。

(2)算法第一步选择S中的活动1,设算法最终得到问题最优解为A={i1, i2, …, ij},则i1=1;(算法第一步正确)
若i1≠1,用1替换i1,可得到A’=(A-{i1})∪{1},集合A’与A中活动个数相同,且1比i1结束的更早,因此与i2, i3, …, ij相容,于是A’也是问题的一个最优解。

(3)假设算法前k步正确,令i1=1, i2, …, ik是前k步顺序选择的活动,则原问题最优解可表示为A={i1=1, i2, …, ik}∪B,令S’是S中剩余的与i1, i2, …, ik相容的活动,即S’={j | sj≥fk, j∈S},则B是S’的一个最优解。

反证法
若不然,假设S’有最优解B’,且|B’| > |B|,那么用B’替换B可以得到的解={i1=1, i2, …, ik} ∪ B’将比A的活动更多,与A为最优解矛盾。

(4)根据第(2)步,子问题S’存在最优解B*={ik+1, …},则
A’={i1=1, i2, …, ik} ∪B*={i1=1, i2, …, ik, ik+1} ∪(B*-{ik+1})为原问题一个最优解,且恰好包含了前k+1步选择的活动。

活动安排问题

meeting.py

s = [1,3,0,5,3,5,6,8,8,2,12]
f = [4,5,6,7,8,9,10,11,12,13,14]

#to Save meeting
# first activity is be added
meeting = [3]

# j is index of f[]
j = meeting[0]-1

# for in 1,len-1
for i in range(1,len(s)):
    if s[i%(len(s))] > f[j%(len(s))]:
        meeting.append(i%(len(s))+1) 
        j = i
print('下面的活动会安排:' , meeting )

非0-1揹包问题

bag.py

#wi
#vi
#
#目标函数:Max(sum(vi*xi))
#
#约束条件:sum(wi*xi)<=C
#         0<=xi<=1
C = 50
w = [10,20,30]
v = [60,100,120]
# C = 150
# w = [35,30,60,50,40,10,25]
# v = [10,40,30,50,35,40,30]
# init v/w
v_w = []
for i in range(len(w)):
    v_w.append(v[i]/w[i])

# 从大到小排序,并且返回响应的索引值list
index = sorted(range(len(v_w)), key=lambda k: v_w[k],reverse=True)


answer = []

# greedy select
def greedy_select(v_w,C):
    left_weight = C 
    all_value = 0
    for i in (index):
        # append 
        left_weight = left_weight - w[i]
        if (left_weight) >= 0:
            answer.append((i+1,1)) # 装第几个箱子,装多少
            all_value = all_value + v[i]
        else:
            left_weight = left_weight + w[i] # 加回来
            answer.append((i+1,left_weight/w[i])) # 装第几个箱子,装多少
            all_value = all_value + v[i] * (left_weight/w[i])
            break
    print('我选择的方案(第n个箱子,装的个数)',answer)
    print('最优解 =',all_value)
greedy_select(v_w,C)

最优装载问题

optimumloading.py

# 目标函数
# max(sum(xi))
# 约束条件
# wi xi <= C
# xi <0,1> , 1 <= i <= n

# 贪心选择策略
# 轻者先装 , 如果重者先装,那么。。。

w = [40,60,20.5,88,94] # 302.5
C = 280

# 可行解是数组
answer = []

#需要排序,该策略是小的在前
index = sorted(range(len(w)), key=lambda k: w[k],reverse=False)


def loading(w):
    left_weight = C 

    for i in index:
        left_weight = left_weight - w[i]
 
        if left_weight > 0:
            answer.append(i+1) 
        else:
            break
    print('我选择的方案,<装第几个箱子>:',answer)
    print('一共装了多少:',len(answer))
loading(w)

哈服满编码,最小生成树,单源最短路径

huffmancode.py

A B C D E
6 7 2 5 9

    29 
13        16
6 7      7  9
        2 5
---
2 5 6 7 9
---
>

---
7 6 7 9
---
>

---
7  9 13
---
>

---
13 16
---
>


---
29
---
>

minimumtree.py

import pygame,sys
pygame.init()
screen = pygame.display.set_mode((800,600))
# 最小生成树
# 连通图的最小连通子图--最优子结构
# Prim & Kruska
# Prim
# 保证连通情况,权重最小的边
# Kruska
# 保证无回路情况,权重最小的边

# 什么时候用Prim算法?
# 稠密图


p_G = pygame.image.load('./p_G.png')
n_G = pygame.image.load('./n_G.png')
k_G = pygame.image.load('./k_G.png')
p_Grect = p_G.get_rect()
n_Grect = n_G.get_rect()
k_Grect = k_G.get_rect()


while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE:
                sys.exit()
            elif event.key == pygame.K_p:
                screen.blit(n_G,n_Grect)
                pygame.display.update()
            elif event.key == pygame.K_k:
                screen.blit(k_G,k_Grect)
                pygame.display.update()
        if event.type == pygame.KEYUP:
            if event.key == pygame.K_p:
                screen.blit(p_G,p_Grect)
                pygame.display.update()
            elif event.key == pygame.K_k:
                screen.blit(p_G,p_Grect)
                pygame.display.update()
    screen.fill((0,0,0))

shorttestpath.py

# 单源最短路径

#给定一个图G = (V, E),其中每条边的权是一个非负实数。另外给定V中的一个顶点v,称为源。求从源v到所有其它各个顶点的最短路径。

#类似prime算法

minimumtree.py

import pygame,sys
pygame.init()
screen = pygame.display.set_mode((800,600))
# 最小生成树
# 连通图的最小连通子图--最优子结构
# Prim & Kruska
# Prim
# 保证连通情况,权重最小的边
# Kruska
# 保证无回路情况,权重最小的边

# 什么时候用Prim算法?
# 稠密图


p_G = pygame.image.load('./p_G.png')
n_G = pygame.image.load('./n_G.png')
k_G = pygame.image.load('./k_G.png')
p_Grect = p_G.get_rect()
n_Grect = n_G.get_rect()
k_Grect = k_G.get_rect()


while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE:
                sys.exit()
            elif event.key == pygame.K_p:
                screen.blit(n_G,n_Grect)
                pygame.display.update()
            elif event.key == pygame.K_k:
                screen.blit(k_G,k_Grect)
                pygame.display.update()
        if event.type == pygame.KEYUP:
            if event.key == pygame.K_p:
                screen.blit(p_G,p_Grect)
                pygame.display.update()
            elif event.key == pygame.K_k:
                screen.blit(p_G,p_Grect)
                pygame.display.update()
    screen.fill((0,0,0))
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章