算法-貪心

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))
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章