---
# System prepended metadata

title: 貪心演算法

---


# 貪心演算法
這個演算法會一直選擇對當前狀況最好的選擇直到結束，
聽起來很饒口，但換句話說，就是不斷執行現在"能夠選擇"、"看起來這個選擇最好"的選項，
之前用過的選項跟目前的選項沒有關係，只會以==眼前所看到的最好的判斷==去做決定，
可以想像的到，這種只挑目前最好的路的演算法，只要不能保證小部分的解是對的，則全域上就絕對不能以這種演算法執行下去。
制定貪心演算法只需幾個步驟
1. 想一個貪心的作法
2. 重複貪心直到程式的結束條件(該條件通常是明確的)
3. 把這個做法以小問題證明一遍(若是小問題的各種邊界條件皆能夠達成，則全域也應能達成)

而貪心演算法的條件大致有:
1. 問題能夠被分而治之
2. 子問題解的產生能夠推移到整體問題的解
3. 不用求出所有子問題的結果

## 使用貪心演算法的一些例子
 
### 0.  bubble sort 
bubble sort就是一個最簡單也能夠理解貪心的例子，我們每次都把最大的元素推向最後面，當然，這個序列就會變成一個降序排列，而每次都把最大的元素推向最後面，就是貪心的相信其他子序列做相同的事情，都會產生同樣的結果，而這就變成了子問題解決後->解決大問題
 
 
###  1. 排程問題
這個算是很經典的題目(? 在停偉學長要我們買的書中也有提到
有n件工作。各工作分別從時間 s~i~ 開始，以時間 t~i~ 結束，做任何工作都得全程參與，做工作的時間線不能重疊，最多能夠參加多少工作?

策略:從可以選擇的工作中不斷選擇結束時間最早的工作

而可行性呢?
我的想法是只要不斷選擇結束時間最早的工作，那麼剩餘的時間理所當然也會是最多的，所以每一次的選擇都是在為後面的工作挪出最大的時間區間，而最大的時間區間本身就是說明"之後也能選最多項工作"，由於我們只需要算出最多能選幾次，不在乎選出的工作有多少種可能，例如:

    ======      工作一
      =====     工作二
           ==== 工作三
###### (=代表工作區間)
以上述例子而言，不管先選的是工作一或工作二，之後接續的工作都應該是工作三，不過對本題來說都無所謂，選的都應該是工作一，因為我們要的只是選擇工作後產生的最大剩餘時間，也就是貪心的選擇最大剩餘子區間。
f(i~r~)代表i~r~的結束時間，
證明:有兩個A,O set，A代表greedy algorithm找出來的解，O代表另一個最佳解，A的集合有{i~1~,i~2~,...i~k~} O是j，先假設他們兩個工作個數一樣，則f(i~r~)<=f(j~r~)，示意:![](https://i.imgur.com/54XJhFW.png)
請看右下角的i跟j，如果f(i~r~)>f(j~r~)，則greegy應該選j~r~才對，所以此情況不合理。
而若|O|=|A|+1，則j~r+1~應該也能被我們的greegy選才對，因為j~k+1~一定在j~k~後面，而f(i~k~)<=f(j~k~)，我們的greedy應該能夠選到才對，矛盾很明顯。

圖片來源:[https://www.youtube.com/watch?v=hZjp35QI-40&list=PLj6E8qlqmkFtoRpLn6IXnH_eboef-3QvZ&index=10&ab_channel=NYCUOCW](https://)
###  2.背包問題the knapsack
w~n~是目前重量，n會從0~W，w[i]是項目重量
盜賊有個能夠承受重量W的袋子，有數個不同價值與重量的東西，這些東西無法被分割，必須在有效時間之前算出最好的總價值並不讓袋子爆炸，ok，這其實是一個要用動態規劃做的題目，但是我認為要解決這個題目的遞迴式也很貪心，每次選擇物品時，只要考慮這東西的重量是否能夠裝進袋子，以及裝進袋子時，這個東西會不會比沒裝時更有價值而已，袋子選擇項目的話，要考慮w~n~-w[i]時的最大價值加上這個項目的價值，以及w[i]時的價值
:::info
v(w[i])代表w~i~的價值
max( v(w~n~),v( w~n~-w[i])+v(w[i]) )
:::
所以價值只在選w~i~時決定，並且只看選項目時剩下的重量最大的價值，也就是每個重量，都貪心的看選完w~i~之後有沒有比較大，並且每個重量都是'最大價值'，所以子項目->下一個子項目也是'最大價值'，這trivial的解釋了為什麼這個方式能行。
範例程式:[https://web.ntnu.edu.tw/~algo/KnapsackProblem.html](https://)
(這其實不符合貪心是不看後照鏡的，但我覺得這也很貪心嘛)

### 3.uva714
有n個人，跟m本書，每本書可以有不同頁數，叫這些人抄書，並且抄書時不能是第1,4,5書這樣抄，只能抄連續序列的書像是2,3,4，抄最多的人要盡量能抄少就抄少，要怎麼做?
我們用二分找出'最大的頁數'，比起列出所有子序列所擁有的最大，我們設一個假設的最大的頁數m，如果這個m找出的人超出所需要的人，就把二分的minimum改為m+1，並進行下一次二分(因為太小所以找出的人太多)，反之就把maximum改成m，直到maximum<minimum為止.
這題用到了貪心的搜尋盡量小的最大頁數，並使用二分搜尋來達到這個結果。
(其實我只是看別人怎麼寫才知道怎麼解釋這題)
https://github.com/Diusrex/UVA-Solutions/blob/master/714%20Copying%20Books.cpp

---

> 推薦別人的筆記
https://hackmd.io/@CLKO/rkhigGlTG?type=view

---
 ### 使用貪心的優點
1. 先把問題以貪心的想法出發，應該很快就能知道這個方法行不行得通，舉個反例就知道問題可不可以就這麼解決
2. 就算行不通，也能從反例知道問題的難點在哪
3. 通常執行速度很快
---
### 缺點
1. 有時候會不知道怎麼證明
2. 貪心是用來短視近利的，不適合解決很多很多問題



