1 貪心演算法 GREEDY ALGORITHM 2 引言 舉例: 工作時,可以用最短時間做最多的事。 出國旅行時,可以用最少的時間玩過最多的地方。 換零錢時,可以換到最少的硬幣。 … 想想看,生活中還有甚麼樣的範例也適用於這樣的演算法概念 呢?你能不能舉出更多的範例? 3 最佳化問題 最佳化問題(Optimization problem)觀念: 一個問題可能有許多解,希望找到一個有最佳數值(最大值或最小 值)的解答,稱為最佳解(或最佳解之一),這類問題稱之為最佳 化問題。 在所有解決最佳化問題的演算法中,「貪心演算法」是最直覺的一種 方法。 4 貪心演算法 觀念: 貪心演算法是每一次選擇中都採取當下看起來最佳的選擇。 希望透過一次又一次局部(Local)最佳解的選擇,最後綜合成為全部 (Global)最佳解的演算法。 更多說明: 每一次選擇是根據某種準則(選擇程序)來決定,而且與前後次的任何 一個決定無關。 用來解決最佳化問題時,通常很簡單而且有效率。 不保證有最佳解。 5 推銷員旅行問題 「推銷員旅行問題」在資訊科學中是一個極為經典的問題(Traveling salesman problem, TSP),下圖為5個城市的地圖以及彼此間的距 離,某個推銷員希望能從城市A出發,繞經所有城市後再回到城市A, 希望能找出總距離最短的路線。 4 A 3 2 E 1 5 1 2 C B 3 D 以貪心演算法的觀念來看,從A城市出發的「選擇準則」 為?___________________________。 得到的總距離為?___________________________。 是最佳解嗎?請解釋「是」或「不是」?______________ _____________________________________。 6 推銷員旅行問題 4 A 3 B 2 E 1 5 1 2 C D 3 7 推銷員旅行問題 「推銷員旅行問題」在資訊科學中是一個極為經典的問題(Traveling salesman problem, TSP),下圖為5個城市的地圖以及彼此間的距 離,某個推銷員希望能從城市A出發,繞經所有城市後再回到城市A, 希望能找出總距離最短的路線。 4 A 3 2 E 1 5 1 2 C B 3 D 以貪心演算法的觀念來看,從A城市出發的「選擇準則」 為?每次在選擇下一個城市的時候,只考慮當前情況, 保證迄今為止經過的路徑總距離最小。 得到的總距離為?13。 是最佳解嗎?請解釋「是」或「不是」?不是,最佳解為11。 8 貪心演算法的演算過程 重複下列步驟直到找出解答為止: 貪心準則(選擇程序) 事先設計好一個選擇局部最佳解的準則,挑選出下一個項目加入到 【解集合】中。 可行性檢查 檢查加入新項目後的【解集合】是否符合題目的要求。 解答檢查 檢查新的【解集合】是否已經是此問題的最終解。 9 貪心演算法的應用-換零錢 有面額1000、500、100、50、10、5、1元的紙鈔與硬幣,如果有 n元,請用最少的紙鈔與硬幣組成。 輸入說明: 每筆測試資料輸入一個正整數n,表示待換的錢,1≤n≤105。 輸出說明: 每筆測試資料輸出一行,表示最少的紙鈔與硬幣組成1000、500、 100、50、10、5、1之數量,中間用空格分隔。 10 貪心演算法的應用-換零錢 有面額1000、500、100、50、10、5、1元的紙鈔與硬幣,如果有 n元,請用最少的紙鈔與硬幣組成。 輸入範例: 28 1000 500 100 50 10 5 1 1000 500 100 50 10 5 1 1541 輸出範例: 0000213 1100401 11 貪心演算法的應用-換零錢 有面額1000、500、100、50、10、5、1元的紙鈔與硬幣,如果有 n元,請用最少的紙鈔與硬幣組成。 輸入範例: 28 1000 0 500 0 100 0 50 0 10 2 5 1 1 3 1000 1 500 1 100 0 50 0 10 4 5 0 1 1 1541 輸出範例: 0000213 1100401 12 貪心演算法的應用-換零錢 貪心準則:先換面額較大的紙鈔或硬幣,換完才換較小的。 1. 依序取出每個紙鈔或硬幣面額,假設目前考慮第i個紙鈔或硬幣,面 額為v[i],求「n/v[i]」的整數,新的n值為「除以v[i]的餘數」。 2. 重覆步驟1,直到所有面額算完為止。 以28元為例: ( [ ]表示取整數,%表示求餘數) 可換 [] = ____個10元。 剩下_______ = _____元,可換 [_____] = ____個5元。 剩下_______ = _____元,可換 [_____] = ____個1元。 13 貪心演算法的應用-換零錢 貪心準則:先換面額較大的紙鈔或硬幣,換完才換較小的。 1. 由面額大到小依序取出每個紙鈔或硬幣面額,假設目前考慮第i個紙鈔 或硬幣,面額為v[i],求「n/v[i]」的整數,新的n值為「除以v[i]的餘數」。 2. 重覆步驟1,直到所有面額算完為止。 以28元為例: ( [ ]表示取整數,%表示求餘數) 可換 [28/10] = 2個10元。 剩下28%10 = 8元,可換 [8/5] = 1個5元。 剩下8%5 = 3元,可換 [3/1] = 3個1元。 14 課堂練習:換零錢 有面額1000、500、100、50、10、5、1元的紙鈔與硬幣,如果有 n元,請用最少的紙鈔與硬幣組成。 v = [1000,500,100,50,10,5,1] n=int(input()) for i in range(7): print( int(n/v[i]),end=" " ) n = n % v[i] 15 貪心演算法的應用-換零錢 想一想,如果多增加了一個18元的面額,請問貪心法則還適用嗎? 請寫下你認為「適用」或「不適用」的原因? 我認為:▢ 適用 因為: ▢ 不適用 16 貪心演算法的應用-換零錢 想一想,如果多增加了一個18元的面額,請問貪心法則可以找到最少 的零錢組合嗎? 請寫下你認為「可以」或「不可以」的原因? 我認為:▢ 可以 ■ 不可以 因為: 28:1(18)+1(10) 25:1(18)+1(5)+2(1) 但 25:2(10)+1(5) 所以驗證不可以 17 課堂練習:悠閒的超商店員 還記得有這樣的經驗嗎?你去買一個10元的東西,你付了1張100元 的鈔票,店員卻找你9個10元,甚至有找你6個10元4個5元和10個1 元的情況。為了避免這樣的情況,某超市在每一間門市都準備了足夠 的零錢,並且要求店員找給顧客的零錢個數一定要是最少的。已知這 個國家使用的貨幣有1、5、10、50、100、500、1000、5000、 10000元等9種,你能幫他解決這個問題嗎? 輸入說明: 每筆測試資料輸入一個正整數n ,代表要找的錢, 1≤n≤105 。 輸出說明: 每筆測試資料輸出一行,表示找給顧客n元時,最少零錢的個數。 18 課堂練習:悠閒的超商店員 輸入範例: 17 99 輸出範例: 4 1個10元+1個5元+2個1元 10 1個50元+4個10元 1個5元+4個1元 請用上一個課堂練習進行改寫 19 課堂練習:悠閒的超商店員 有面額10000、5000、1000、500、100、50、10、5、1元的紙鈔 與硬幣,如果有 n元,請用最少的紙鈔與硬幣組成。 c=0 v = [______________________] n = ________________ for (_________________ ) c = c + __________ n = __________ print(c) 20 貪心演算法的應用-工作排程問題 有n個工作要交給一台機器,每個工作有選定的開始時間與結束時 間,每次只能執行一個工作,而且工作一旦開始就必須完成,不能切 換到另一個工作,假設工作切換時間很快,可以忽略不計,請問最多 可以完成幾個工作? 輸入說明: 第一行有一個正整數n,表示需要執行的工作個數,n<150。接 下來有n行,每一行有兩個正整數s與e,分別表示工作的開始時 間與結束時間,1≤ s, e≤1000,且s<e。 輸出說明: 輸出一個數字,表示結束時最多完成幾個工作。 21 貪心演算法的應用-工作排程問題 輸入範例: 6 1 11 69 26 8 10 48 14 輸出範例: 3 time Job 1 2 3 4 5 6 1 2 3 4 5 6 7 8 9 10 11 22 貪心演算法的應用-工作排程問題 先做結束工作最早的工作6。 再選擇開始時間等於或晚於工作6結束時間的工作5。 最後選擇工作4。 可完成的工作共有3件。 time Job 6 5 4 1 2 3 4 5 6 7 8 9 10 11 23 貪心演算法的應用-工作排程問題 貪心準則: 結束時間最早的工作,而且沒有與已經執行的工作衝突的工作先做。 先將n個工作以_______的先後來排序。 由最前面取出第1個工作,工作取出後,表示這個工作送進機器執 行,可以執行的工作數增加1。 所有剩餘的工作中,若開始時間早於正在執行工作的結束時間,則放 棄執行此工作,直到找到開始時間等於或晚於正在執行工作的結束時 間,將找到的工作放進機器執行,可以執行的工作數增加1。 重覆上述步驟直到檢查完所有工作,即可得到最多可完成的工作數。 24 貪心演算法的應用-工作排程問題 貪心準則: 結束時間最早的工作,而且沒有與已經執行的工作衝突的工作先做。 先將n個工作以結束時間的先後來排序。 由最前面取出第1個工作,工作取出後,表示這個工作送進機器執 行,可以執行的工作數增加1。 所有剩餘的工作中,若開始時間早於正在執行工作的結束時間,則放 棄執行此工作,直到找到開始時間等於或晚於正在執行工作的結束時 間,將找到的工作放進機器執行,可以執行的工作數增加1。 重覆上述步驟直到檢查完所有工作,即可得到最多可完成的工作數。 25 課堂練習:工作排程 有n個工作要交給一台機器,每個工作有選定的開始時間與結束時 間,每次只能執行一個工作,而且工作一旦開始就必須完成,不能切 換到另一個工作,假設工作切換時間很快,可以忽略不計,請問最多 可以完成幾個工作? 輸入範例: 6 1 11 69 26 8 10 48 14 輸出範例: 3 就上頁範例而言 課堂練習:工作排程 n=int(input()) S=[0 for i in range(n)] E=[0 for i in range(n)] for i in range(n): s,e = map(int,input().split()) S[i]=s E[i]=e s:start time e:end time for i in range(n-1 ) : for j in range(n-1-i): if E[j]>E[j+1]: temp=E[j] E[j]=E[j+1] E[j+1]=temp temp=S[j] S[j]=S[j+1] S[j+1]=temp count=1 end=E[0] for i in range(1,n): if (S[i]>=end): count=count+1 end =E[i] print(count) index S 0 261 E 1 2 6 2 4 8 3 6 9 4 8 10 5 1 11 4 27 貪心演算法的應用-誰先晚餐 有n個人在同一家餐廳吃晚餐,每個人點的餐,廚師煮的時間都不一 樣,而每個人吃完時間也不一樣。而餐廳一次只能煮一道菜,請問廚 師要如何安排煮的順序,才能最早讓所有人都吃完離開。 輸入說明: 第一行為一個整數n,代表用餐人數,n≤105。接下來有n行,每行有兩 個正整數c與e,分別代表每個人的餐點準備時間與食用時間,1≤c,e≤ 105。 輸出說明: 輸出結果,表示在廚師烹煮的最佳情況下,最後一個人的離開時間。 28 貪心演算法的應用-誰先晚餐 有n個人在同一家餐廳吃晚餐,每個人點的餐,廚師煮的時間都不一 樣,而每個人吃完時間也不一樣。而餐廳一次只能煮一道菜,請問廚 師要如何安排煮的順序,才能最早讓所有人都吃完離開。 解題關鍵:你的貪心準則是甚麼? ▢ 煮最慢的先做 ▢ 煮最快的先做 ▢ 吃最快的先做 ▢ 吃最慢的先做 29 貪心演算法的應用-誰先晚餐 有n個人在同一家餐廳吃晚餐,每個人點的餐,廚師煮的時間都不一 樣,而每個人吃完時間也不一樣。而餐廳一次只能煮一道菜,請問廚 師要如何安排煮的順序,才能最早讓所有人都吃完離開。 解題關鍵:你的貪心準則是甚麼? ▢ 煮最慢的先做 ▢ 煮最快的先做 ▢ 吃最快的先做 ■ 吃最慢的先做 30 貪心演算法的應用-誰先晚餐 如果輸入下列數字,需要多少時間才能讓所有人離開? Case 1: 2 11 8 7 10 Case 2: 3 1 1 2 2 3 3 Case 3: 3 9 18 4 6 7 10 31 貪心演算法的應用-誰先晚餐 如果輸入下列數字,需要多少時間才能讓所有人離開? Case 1: 2 11 8 7 10 Case 2: 3 1 1 2 2 3 3 Case 3: 3 9 18 4 6 7 10 Ans: 26 Ans: 7 Ans: 27 課堂練習:誰先晚餐 n=int(input()) # 客人數量 C=[0 for i in range(n)] #準備時間 E=[0 for i in range(n)] #食用時間 for i in range(n): C[i],E[i]=map(int,input().split()) cooktime=0 totaltime=0 # 依照食用時間排序 由大到小 for i in range(n-1 ) : for j in range(n-1-i): if E[j]<E[j+1]: temp=E[j] E[j]=E[j+1] E[j+1]=temp temp=C[j] C[j]=C[j+1] C[j+1]=temp for i in range(n): cooktime = cooktime + C[i] if (cooktime+E[i]>totaltime): totaltime=cooktime+E[i] print(totaltime) 32 33 貪心演算法的應用-背包問題 只要做貪心演算法,一定會遇到的經典題 -背包問題 (Fractional Knapsack)。 假設有n個物品及一個背包,已知背包的負重能力與每個物品的價值 與重量,可以將物品分割後,只取部分放入背包,求在背包的負重能 力範圍內,放入背包所有物品的最大價值。 34 貪心演算法的應用-背包問題 輸入說明: 第一行有一個正整數n,表示物品個數,n<100。 接下來有n行,每一行有兩個正整數w與v,分別 表示物品的重量與價值,1≤w, v≤100。最後有 一個正整數k,表示背包的負重能力, k<1000 。 輸入範例: 3 6 12 44 7 21 15 輸出說明: 輸出一個數值(四捨五入至小數第二位),表示在背 包的負重能力範圍內,放入背包所有物品的最大 價值。 輸出範例: 35.00 35 貪心演算法的應用-背包問題 想一想: 貨物 ❶ 重量:6 價值:12 貨物 ❷ 重量:4 價值:4 放入背包所有物品的最大價值 _____________。 貨物 ❸ 重量:7 價值:21 解題關鍵: 你的貪心準則是甚麼? 36 貪心演算法的應用-背包問題 想一想: 貨物 ❶ 重量:6 價值:12 貨物 ❷ 重量:4 價值:4 放入背包所有物品的最大價值 35。 貨物 ❸ 重量:7 價值:21 解題關鍵: 你的貪心準則是甚麼? 先計算所有物品的單位重 量的價值,將所有物品以 單位重量的價值由大到小 進行排序,取最大的單位 重量的價值物品開始放。 37 貪心演算法的應用-背包問題 貪心準則:先計算所有物品的單位重量的價值,將所有物品以單位重 量的價值由大到小進行排序,取最大的單位重量的價值物品開始放。 若可以放進背包就放入背包,一直到最後放不下或所有物品都已放 入為止。 最後放不下的部分,取剩餘未放入物品的最高單位重量的價值物品 填滿到背包重量的上限,即可求得背包的負重能力範圍內,放入背 包所有物品的最大價值。 38 貪心演算法的應用-背包問題 步驟1:選擇單位重量的價值最大的物品3先放,因為背包負重大於物品3的 重量,所以可全部放入。 15 - 7 = 8,背包負重剩8。 價值為0 + 21 = 21。 步驟2:因為背包還沒滿,選擇第 物品 重量 價值 1 2 3 6 4 7 12 4 21 單位重量的價值 ( = 價值/重量 ) 2 1 3 二大的物品1放入,背包剩餘負重 還是大於物品1,所以可全放入。 步驟3:背包還沒滿,繼續放,物品2 8 - 6 = 2,背包負重剩2。 無法全部放入,只能放_____單位。 價值為21 + 12 = 33。 價值為________________。 39 貪心演算法的應用-背包問題 步驟1:選擇單位重量的價值最大的物品3先放,因為背包負重大於物品3的 重量,所以可全部放入。 15 - 7 = 8,背包負重剩8。 價值為0 + 21 = 21。 步驟2:因為背包還沒滿,選擇第 物品 重量 價值 1 2 3 6 4 7 12 4 21 單位重量的價值 ( = 價值/重量 ) 2 1 3 二大的物品1放入,背包剩餘負重 還是大於物品1,所以可全放入。 步驟3:背包還沒滿,繼續放,物品2 8 - 6 = 2,背包負重剩2。 無法全部放入,只能放2單位。 價值為21 + 12 = 33。 價值為35。 40 貪心演算法的應用-吃水果增強免疫力 n=int(input()) # 物品種類數量 V=[0 for i in range(n)] #物品價值 W=[0 for i in range(n)] #物品重量 CP=[0.0 for i in range(n)] #物品CP for i in range(n): W[i],V[i]=map(int,input().split()) CP[i] = V[i]/W[i] k=int(input()) # 背包可放的重量 totalv=0 # 依照CP 由大到小 for i in range(n-1 ) : for j in range(n-1-i): if CP[j]<CP[j+1]: temp=CP[j] CP[j]=CP[j+1] CP[j+1]=temp temp=V[j] V[j]=V[j+1] V[j+1]=temp temp=W[j] W[j]=W[j+1] W[j+1]=temp #由CP值大的物品開始放 for i in range(n): if (W[i]<k): totalv=totalv+V[i] k = k - W[i] else: totalv = totalv+CP[i]*k break print(totalv) 41 不適用貪心演算法的應用-0/1背包問題 0/1背包問題:假設有n個物品及一個背包,已知背包的負重能力與每 個物品的價值與重量,每個物品只能取或不取,無法只取一部分放入 背包,求在背包的負重能力範圍內放入背包所有物品的最大價值。 不是所有問題都可以使用貪心演算法解題,有很多問題不適合使用貪 心演算法。 物品 1 2 3 重量 價值 單位重量的價值 ( = 價值/重量 ) 6 12 2 8 14 1.75 7 21 3 假設背包最多負重15KG 貪心演算法 最佳解 12 21 14 21 33 35 42 貪心演算法的應用-吃水果增強免疫力 隨著全球武漢肺炎疫情持續延燒,全球呈現戒備狀態,除了勤洗手、 戴口罩與環境進行多消毒,提升個人的身體免疫力至關重要,特別是 維生素C,可透過蔬菜水果的食用來攝取。 右表為常見水果中維生素C含量最高的 水果與價格,請問在希望每天水果花 費不超出m元的前提之下,應購買那 些水果才能獲得最高的維生素C含量? (假設水果可以任意切片購買所需的克 數,每種水果攝取量不超過100克) 水果 每100克含維生素C 含量(mg) 每100克價格 柳橙 58 5 檸檬 56 7 鳳梨 80 4 草莓 85 20 奇異果 90 10 芭樂 245 8 43 貪心演算法的應用-吃水果增強免疫力 輸入說明: 第一行有一個正整數n,表示水果的種類數,n<100。接下來有n行,每 一行有兩個正整數c與p,分別表示每100克含維生素C含量(mg)與每 100克價格,1≤c,p≤300。最後有一個正整數m,表示每天水果的最 高花費限制, m<1000 。 輸出說明: 輸出一個數值(四捨五入至小數第二位),表示在每天水果的花費範圍內, 可以攝取的最多維生素C含量。 44 貪心演算法的應用-吃水果增強免疫力 請先算出每一樣水果單位價格下的維生素含量(CP值): 水果 每100克含維生素 C含量(mg) 每100克價格 柳橙 58 5 檸檬 56 7 鳳梨 80 4 草莓 85 20 奇異果 90 10 芭樂 245 8 單位價格之 維生素C含量 解題關鍵: 你的貪心準則是甚麼? 45 貪心演算法的應用-吃水果增強免疫力 請先算出每一樣水果單位價格下的維生素含量(CP值): 水果 每100克含維生素 C含量(mg) 每100克價格 單位價格之 維生素C含量 柳橙 58 5 11.6 檸檬 56 7 8 鳳梨 80 4 20 草莓 85 20 4.25 奇異果 90 10 9 芭樂 245 8 30.625 解題關鍵: 你的貪心準則是甚麼? 先計算所有水果的單位價 格的維生素C含量,將所 有水果以單位價格的C含 量由大到小進行排序,取 最大的單位價格的C含量 水果開始放。 46 貪心演算法的應用-吃水果增強免疫力 輸入範例: 輸出的結果應該是多少? 6 58 5 56 7 80 4 85 20 6種水果 每100公克之維他命C含量 每100公克之價格 90 10 245 8 30 假設購買水果的花費最多30元 即花費30元的狀況下,最多 可攝取?mg的維生素C。 47 貪心演算法的應用-吃水果增強免疫力 輸入範例: 輸出的結果應該是多少? 6 58 5 56 7 80 4 85 20 6種水果 每100公克之維他命C含量 每100公克之價格 90 10 245 8 30 假設購買水果的花費最多30元 即花費30元的狀況下,最多可 攝取497.00mg的維生素C。 =245+80+58+90+24 (8) (4) (5) (10) (3)
You can add this document to your study collection(s)
Sign in Available only to authorized usersYou can add this document to your saved list
Sign in Available only to authorized users(For complaints, use another form )