本文章題目和算法本身來自《算法設計與分析》(屈婉玲版),黑書(劉汝佳),理解爲本人理解。如有補充或不同見解歡迎在下方留言區討論。
目錄
- 哈夫曼樹
- 最小生成樹:Prim
- 例:釣魚
- 例:照亮的山景
- 例:過河問題
哈夫曼樹
算法描述
爲獲得平均長度最短的編碼,不斷將字符集中使用頻率最小的兩個字符取出(不放回),合併成爲一棵子樹,將父節點作爲一個字符放回字符集,使其頻率爲兩個子節點的權值之和。這樣構造的樹是一棵提供最優編碼的樹,每一條從樹根到樹葉的路徑都是一個字符的編碼
核心問題
- 爲什麼每次要選取兩個頻率最小的字符(歸納基礎)
- 證明牽扯到樹的變化,而有關優化目標總是和樹的高度有關,有失一般性,怎樣處理?
試證
- 對於一個最優方案對應的二叉樹T,倘若我將頻率最低的兩個子節點放到最底層,那麼我就可以把它們合併,將二叉樹規模縮小,運用歸納假設構造一個最優解
- 倘若我可以知道合併節點之後前後兩棵樹的關係,我就可以把這步貪心決策和這棵新樹合併,證明它也有最優性。但首先需要先證明T合併之後的那棵樹也是個最優的樹
引理4.2
設是最優二叉編碼樹T 中頻率最小的兩個葉子節點,與最底層兩個葉子節點,y$交換後不會改變樹的最優性。顯然有:
引理4.3
爲二叉樹T的兩片葉子,設將其合併後新樹爲,則兩棵樹的關係爲:
正式證明
- 由於不是按步驟歸納而是按規模歸納,所以第一步不是最重要的推理
- 時結論顯然
- 假設時成立。對於一棵有個字符的二叉編碼樹,我們可以把兩片頻率最小的葉子放到最下面而不影響最優性
- 將其合併成節點獲得樹T’,則可以根據貪心算法用T‘的葉子節點的權值構造最優二叉編碼樹T*
- T’也是一棵最優二叉編碼樹,否則B(T’)>B(T*),兩邊同時加f(a),f(b),左邊變成B(T),右面是將填到下面得到的新樹,顯然T的最優性失效,矛盾
- 所以把填到下面構成的新樹的平均編碼長度與最優編碼相等,它也是個最優編碼:使用貪心想法構成的最優編碼
套路總結
對於歸納問題規模型貪心,有以下套路:
- 對於規模爲的問題,證明貪心操作所涉及的元素不會影響到最優性(如挪節點)
- 合併,縮小問題規模爲,用歸納假設:規模爲時可用貪心構造
- 證明也是最優解,因爲和同規模,故展開後也同規模,故用貪心構造出的解對於規模也是最優解
講的很抽象,💊多練習。
最小生成樹:Prim
算法綜述
- 將圖G的頂點分爲兩個集合:處理過的和未處理過的
- 選擇連接和的最短的邊,並將側的與相連的點加入到中
- 重複以上算法,直至爲空
證明思路
- 與上一題不同,本題採用對貪心的步驟進行歸納,而非問題的規模
- 證明的關鍵在於第一步:使用第一步的證明作爲後續子問題的歸納基礎
- 通用思路:假設存在使第k步成立的最優方案,對於問題中剩下未處理的部分證明它必須用最優子問題的解法與前k步成立才能得到最終的最優方案
- 利用歸納基礎:子問題的第一步可以用貪心算法,故構造了一個包含前k+1步貪心決策的最優決策。
證明實戰
- 第一步必須是選擇權值最小的邊,否則若使用的是,在最終生成的樹中若加入則生成含的圈,破除後剩下的仍是一棵生成樹,但總長下降,與最優性矛盾
- 假設存在最小生成樹包括前k步選擇的邊,構成了已處理點集和未處理點集,根據最小生成樹的定義,的結構必須是中已經出現的樹+將看成一個大點後剩下點的生成樹合併的結果,運用第一步歸納假設即可證畢。
例:釣魚
題目描述
在一條水平路邊,有個釣魚湖,從左到右編號爲1、2、3、……、n.佳佳有個小時的空餘時間,他希望用這些事件釣到儘量多的魚。他從湖1出發,向右走,有選擇的在第個湖邊停留一定的時間釣魚,最後在某一個湖邊結束釣魚。佳佳測出從第i個湖到第個湖需要走分鐘的路,還測出在在第個湖邊停留,第一個5分鐘可以釣到魚,以後再每釣5分鐘魚,魚量減少,爲了簡化問題,佳佳假定沒有其他人釣魚,也不會有其他因素影響到他釣到期望數量的魚。請設計算法給出佳佳能釣到最多的魚的方案。
問題抽取
- 變量太多了,行走時間,停留時間
- 湖比較少,我們枚舉最後停留的湖,把行走時間變成常量
- 問題中以5分鐘作爲基本單位,不妨把5去掉
- 行走時間爲常量,那問題等價爲佳佳可以瞬間移動
貪心策略
- 在第分鐘瞬移到可以收穫最多魚的湖去抓魚,更新這個湖的抓魚量
- 第一步正確性顯然,若存在最優解包含前步選擇,則剩下的時間內也應是剩下時間內的最優選擇,故可用第一步構造處使用貪心算法的解與前步成立
- 證明較顯然故略去
- 最後不要忘記將中情況合併
複雜度
- 暴力枚舉各時刻可獲魚數最大值:
- 堆優化:
總結
感覺問題爲貪心解法時應注意控制可變量的個數,明確優化對象,方便思考
例:照亮的山景
題目描述
在一片山的上空,高度爲處有個處於不同水平位置的燈泡。如果山的邊界上某一點與燈i的連線不經過山上的其他點,我們稱燈i可以照亮該點。開儘量少的燈,使得整個山景都被照亮
優化對象選擇
- 選擇電燈?
- 區間是碎的,難以處理。(圖先欠着)
如果向下看
- 所有的可行方案都照亮了所有的谷底
- 所有照亮所有谷底的方案都是可行方案(光路是可逆的)
- 能照亮一個谷底的燈必定是一個連續的區間(圖先欠着)
那我們直接以谷底優化對象好了
算法綜述
- 對每一個谷底,預處理能將其照亮的所有燈泡區間
- 選擇最少的燈泡,使得每個區間中至少有一個燈泡被選中了(貪心)
貪心決策(做有智商的莽夫)
- 顯然的決策:如果區間包含了區間,那麼考慮區間的決策是無用的,因爲必有一點在中,自然滿足
- 只需討論所有部分重合和不重合的區間
- 莽夫:最左側的區間是最危險的區間,那麼就考慮它,選它最右面的點,以保證能照亮更多與它重合的區間,把這些被照亮的區間刪去
證明
- 以步數做歸納,顯然莽夫的思考過程就是我們的決策基礎
- 若存在最優決策T包含前k步的決策,若再處理已選燈的區間是多餘的,去掉他們,應對後面的區間進行最優決策,而由歸納基礎得出存在以貪心決策開頭的方案使得其爲最優方案
- 都是一個套路。。。
- 時間複雜度:直接線性掃描,爲
例:潛泳比賽
題目描述
- 有一支由人組成的潛水隊參與比賽,目標是全隊游到對岸。
- 潛水需氧氣筒,整隊只有一個氧氣筒。
- 氧氣筒可以兩人公用,但速度就是兩人中較慢者的速度。
- 任意兩人可以一同潛泳。
- 請設計最優方案,使得最後一名選手到達對岸的時間儘量早。
莽夫思路一
- 總需要一個人來把氧氣筒送回來,而遊得再快的人也會被遊得慢的人拖累,不妨就讓遊得最快的人來回送氧氣筒
莽夫思路二
- 如果讓最慢的兩個人一起過去,在對岸安排好送氧氣筒回來的人怎麼樣?
- 把最快的兩個人先送過去,讓他們充當搬運工
請計算
- 1、 2、 5、 6 、8、 9
- 1、 2、 2、 2、 2、 2
如果合併這兩種思路
- 這兩種思路的共同點,就是把最慢的兩個人送過去了,而對於不同的情況有不同的選擇
- 若將所有人按照過河時間升序排序成,那麼易知如果時用算法1,反之用算法2,我們就能最快地把最慢的兩個人送到對岸去
- 這樣選擇研究的對象看起來和諧了一些
證明歸納基礎
- 歸納基礎:將最慢的兩個人先用最快的方式送過去,不會影響總時間
- 倘若存在最優策略不是這樣:最慢的兩個人要麼是一起過,要麼是拖累着別人過。
- 這兩個人如果是一起過的,那就得有人回來送氧氣筒。如果對面有人的話肯定不是他們兩個中的一個回來送氧氣筒。如果不是回來送,把調到前面去會更優。那不如把他們的過河順序都調到前面去
- 如果這兩個人是分開過的,那麼還是用去送氧氣筒最快,那麼爲什麼不把順序調到前面呢?
- 完整證明思路與前面基本一樣,節省時間略去不提
- 說不太清楚,有更好的思路請到我的萬年不更的博客下留言討論
時間複雜度
- 只需線性掃描,結束
總結
!找好優化目標!
練:澆花問題
- 有一長方形花壇,在於其較長邊平行的中軸線上安放了若干水龍頭,每個水龍頭能澆到草地的半徑是已知的。
- 保證存在可以把所有草地都澆到的方案,請把其中一個選擇水龍頭最少的方案找出來