貪婪法(Greedy)
Greedy基本上就是一種簡化型的DP,當你可以確定當前狀況就是接下來最好的狀況時,就可以
直接使用了。也就是直接認為目前最好的,到了下一步還是會是最好的解,這無疑是一種很符合 人性貪婪一面的算法。
用介紹的實在很難說清楚,就讓我們直接來看例題吧!
※例題 1 ─ 工作排程1
給你n個事件,每一個事件都有它的開始時間和結束時間,而在一個時間內最多只能夠有一個事 件,請問最多總共可以進行幾個事件?
※例題 2 ─ 工作排程2
給你n個工作,每個工作都有其截止期限ti,而如果你在時限前沒做那個工作的話,則要付罰金 ci。如果做一個工作需要1單位的時間,則你最少要付多少罰金?
※例題 3 ─ 誰先晚餐 ( TIOJ 1072 )
給你n個要吃晚餐的人和一個廚師。當然那些人可以同時一起吃,但廚師一次只能做一道菜。給定 每個人要吃的菜需要做多久,以及那個人需要吃多久,試問至少要多少時間,才能讓全部人都吃 完?
※例題 4 ─ Setting Problems ( ACM 11269 )
給你n個工作,每個工作都分為前段跟後段,各需要ai和bi的時間。現在有兩台機器,一台負責處 理前段工作,一台負責處理後段工作。而一個工作前段處理完後才能處理後段。請問至少要多少時 間才能處理完所有工作?
※例題 5 ─ Shoemaker's Problem ( ACM 10026 )
給你n個工作,你每項工作需要花ti天才能完成,而從你開始工作算起,每過一天,如果第i個工 作沒有完成的話,你就要付出ci的罰金,請問你要以何種順序進行這n項工作,才能使付出的罰 金最少呢?
※例題 6 ─ 背包問題
給你n個物品,每個物品都有其數量和價值,現在你有一個可以裝w個東西的背包,請問你最多 可以裝到多少價值的東西?
※例題 7 ─ Minimal Coverage ( ACM 10020 )
給你n段線段[ai, bi],請問你至少需要幾段線段,才能覆蓋住[0, M]這段線段?
※例題 8 ─ LIS but not LIS ( TIOJ 1240 )
給你一個有n個正整數的序列,請你把它分拆成最少條的序列,使得每個序列都是嚴格遞增的。
※例題 9 ─ 經濟編碼 ( TIOJ 1155 )
給你一個要壓縮的純文字檔案,壓縮方法是把每一個字元轉換成一個由0和1組成的序列。但是為 了可以分辨所有的字元,你要確定沒有一個序列會是另外一個序列的前綴。現在給你每個字元出 現的次數,請問你要如何編碼才能使最後編出來的字串最短?
Example: 原先的編碼方式:
字元/出現次數 ‘a’/5 ‘b’/3 ‘c’/4 ‘d’/9 ‘e’/6 原本二進位碼 1100001 1100010 1100011 1100100 1100101 原本檔案長度是7*5 + 7*3 + 7*4 + 7*9 + 7*6 = 189 bits。
其中一種最佳的對應方法:
新的二進位碼 10 000 001 01 11
這麼編碼的檔案長度是2*5 + 3*3 + 3*4 + 2*9 + 2*6 = 61 bits。
※例題 10 ─ Packets ( ACM 311 )
給你一些1*1、2*2、3*3、4*4、5*5、6*6的貨物,而你要把他們裝進一些6*6的貨櫃中,請問最少需 要多少個貨櫃?
※例題 11 ─ Camel trading ( ACM 10700 )
給你一個由正整數、加號和乘號組成的算式,請問在加上括弧後,這個運算式的最大值和最小值 是多少?
※例題 12 ─ Product of digits ( ACM 993 )
給你一個正整數n,請你找出一個最小的正整數Q,使得Q的每個位數乘積是n。
※例題 13 ─ 零錢問題
給你無限量個一元、五元、十元、二十元、五十元、一百元的硬幣,現在你要湊出n元來,請問最少 需要多少個硬幣?
※例題 14 ─ Shopaholic ( ACM 11369 )
給你n樣物品的價錢,你現在每買三樣以上的物品,最便宜的那個物品就不用錢。請問在買完全部 物品後,你最多共可以省下多少錢?(和所有物品的總價錢相比)
※例題 15 ─ 寵物雞問題 ( TIOJ 1231 )
給你一個電子寵物雞遊戲,遊戲中有若干種食物,每種食物都有固定的熱量、保存期限。每分鐘你 可以從這些食物中選擇一種餵食寵物雞,但不可餵食過期的食物。而餵食每單位熱量會使體重增 加1公斤,而如果這分鐘沒有餵食,體重會減少1公斤。給定的食物種類、熱量、保存期限,以及 終止時間,找出最大的體重增加量。
※例題 16 ─ The Grand Dinner ( ACM 10249 )
給你m個團體和n張桌子,第i個團體有ai個人,第j桌子最多只能坐bj個人。現在每個團體的人 都不想和自己同一個團體的人坐同一張桌子,請問有沒有滿足上列條件的安排方式,如果有請輸 出其中一種安排方式。
※例題 17 ─ 刪位數的問題 ( TIOJ 1397 )
給你一個 n 位數的正整數 A,請問刪除其中 k 位數 ( k < n )、將剩下的數字依序合併形成一個新的 正整數B,B的最小可能值是多少?請注意,A和B的首位都不能是0。
※例題 18 ─ Minimum Sum LCM
給你一個正整數n,你要找到兩個以上的正整數,使得這些正整數的最小公倍數是n,且這些數的 和最小,請問這個和最小是多少?
※例題 19 ─ 超級撈魚活動
給你一條直線上的n個魚池,在給定的時間之內,從入口開始,沿途撈魚。每一單位的時間都可以 撈一次魚,而在每一個魚池第一次撈魚所獲得的魚數量為 Fi,第二次以後在相同魚池所撈的魚穫 量都會比前一次少Di個。此外,來往於兩個魚池之間也需要花時間,請問你在限時內最多可以撈 多少魚。
※例題 20 ─ Ferry Loading II ( ACM 10440 )
給你m個人要過河,每個人到達碼頭的時間分別為ti,而你現在只有一艘船,這艘船最多可以載 n個人過河,而這艘船需要花t分鐘到對岸,再花t分鐘回到出發處。假設上下船不需要時間,請 問最後一個人到達對岸的時間最早是多少?而船至少要出發幾次才能將所有人運至對岸?
※例題 21 ─ Work Reduction ( ACM 10670 )
給你n單位的工作,你現在有兩種操作,一種是花費A元將工作量減一,一種是花費B元將工作 量減半(無條件捨去),你現在希望工作量恰好降到m單位,請問你至少需要花多少錢?
※例題 22 ─ MiniMice ( ACM 11411 )
給你n個正整數,每個數的強度定義為他的正因數個數。你現在要把這n個數排成一圈,使得相鄰 兩個數的強度差的最大值最小,請問這個最小值是多少?
※例題 23 ─ 搭帳棚問題 ( 2007 TOI二階模擬考 )
給你n個攤位排成一直線,每個攤位的寬度分別為wi,你現在要訂做p個寬度為s的帳棚,每個 帳棚最多只能覆蓋r個攤位,而每個攤位都要被某個帳棚完全覆蓋。現在給定wi、p和r,請問帳篷 寬度s最小要是多少?
※例題 24 ─ 照亮的山景 ( TIOJ 1404 )
給你一條山稜線,上方架設了一條直線,你希望在這條直線上架設盡量少的 燈泡,使得這條山稜線上的每一點都可以被照亮。給定山峰折線的n個頂點,
以及線路高度T。試以儘量少的燈泡(如左圖中的B1,B2)照亮整個山巒。
看完上面這許多的題目後,相信大家都能體會什麼是Greedy了,Greedy其實可以是很有趣又不容 易的啊!
相關題目:ACM 10954, 11054, 11157, 11264 TIOJ 1396, 1397, 1398, 1401, 1405, 1406, 1408
並查集(Disjoint Set)(Union Find)
並查集是一個很特別的資料結構,在並查集中有若干個元素,每個元素屬於某個集合Si,而每個 集合Si則由其中的一個元素來代表。剛開始其中每個元素都分別屬於一個集合,而並查集支援兩 種操作:找出某元素所在集合和將兩個集合合併。
並查集的概念
並查集實作時會是一個森林(稱為disjoint set forest),每棵樹就是一個集合,而以那棵樹的樹根 作為那個集合的代表。對每個元素,我們記錄它的母節點,要找到一個元素所在的集合,就只要 一直往母節點找就可以了,而如果要合併集合時,就將一個集合的樹根的母節點設為例外一個集 合的樹根就好了。
為了使操作時更為迅速,我們有兩個重要的策略:path compressing和union by rank。
Path compressing:
在你尋找一個數所在集合時,每次都要往上追到樹根,才能知道這個數所在的集合,但假如我們 做了很多次一樣的查找的話,那不就很浪費時間了嗎?所以我們在每次查找時,將沿途的所有節 點的母節點直接指向樹根,這樣下次在找這些點時,就只要往上找一層就找到了!
Union by rank:
要使查找時的時間盡量減少,我們自然希望每棵樹的高度越小越好。為了這個目的,我們對於節 點,記錄它以下的子樹的深度,當要合併兩棵樹時,就將比較不深的樹的樹根接到比較深的樹的 樹根下面。
當然在path compressing時,樹的深度有可能會有變化,但我們只是為了概略的降低時間複雜度,
既然不影響正確性,這是沒有關係的。
並查集的實作
對於每個節點x,我們記錄它的母節點位置。而為了便於函數實作,樹根的母節點則指向自己。
Pseudocode:
‧合併Union(x, y)
把x和y所屬的集合合併。
UNION (x, y)
1 LINK (FIND-SET(x), FIND-SET(y))
LINK (x, y)
1 if x.rank > y.rank 2 then y.parent ← x 3 else x.parent ← y 4 if x.rank = y.rank
5 then y.rank ← y.rank +1
‧查找Find-Set(x)
查找x屬於哪個集合,回傳x所屬集合的代表。
FIND-SET (x) 1 if x.parent x
2 then x.parent ← FIND-SET (x.parent) 3 return x.parent
Union Find的均攤分析時間複雜度為O(mα(n)),其中m為總共進行了幾次Union-Find操作,n為
元素總數,α(n)為Ackermann函數的反函數,其值在n< 時<5,所以幾乎可視為常數。
※例題 ─ Friends ( ACM 10608 )
給你一個有N個居民的小鎮。當然其中有許多人是朋友的關係。根據有名的諺語:「我朋友的朋友 也是我的朋友」,所以如果A和B是朋友,B和C是朋友,那麼A和C也是朋友。你的任務是算出 在這個鎮中最大的朋友集團為多少人。
相關題目:ACM 10158, 10505, 10842 TIOJ 1312
挑戰題:TIOJ 1163