進階貪心算法例解

本文章題目和算法本身來自《算法設計與分析》(屈婉玲版),黑書(劉汝佳),理解爲本人理解。如有補充或不同見解歡迎在下方留言區討論。

目錄

  • 哈夫曼樹
  • 最小生成樹:Prim
  • 例:釣魚
  • 例:照亮的山景
  • 例:過河問題

哈夫曼樹

算法描述

爲獲得平均長度最短的編碼,不斷將字符集中使用頻率最小的兩個字符取出(不放回),合併成爲一棵子樹,將父節點作爲一個字符放回字符集,使其頻率爲兩個子節點的權值之和。這樣構造的樹是一棵提供最優編碼的樹,每一條從樹根到樹葉的路徑都是一個字符的編碼

核心問題

  • 爲什麼每次要選取兩個頻率最小的字符(歸納基礎)
  • 證明牽扯到樹的變化,而有關優化目標總是和樹的高度有關,有失一般性,怎樣處理?

試證

  • 對於一個最優方案對應的二叉樹T,倘若我將頻率最低的兩個子節點放到最底層,那麼我就可以把它們合併,將二叉樹規模縮小,運用歸納假設構造一個最優解
  • 倘若我可以知道合併節點之後前後兩棵樹的關係,我就可以把這步貪心決策和這棵新樹合併,證明它也有最優性。但首先需要先證明T合併之後的那棵樹也是個最優的樹

引理4.2

x,yx, y是最優二叉編碼樹T 中頻率最小的兩個葉子節點,與最底層兩個葉子節點xx,y$交換後不會改變樹的最優性。顯然有:
B(T)B(T)=[f(x)f(a)][dT(x)dT(a)]+[f(y)f(b)][dT(y)dT(b)]0 B(T)-B(T^{'})=[f(x)-f(a)][d_T(x)-d_T(a)]+[f(y)-f(b)][d_T(y)-d_T(b)]\ge 0

引理4.3

x,yx, y爲二叉樹T的兩片葉子,設將其合併後新樹爲TT^{'},則兩棵樹的關係爲:
B(T)=B(T)+f(x)+f(y) B(T)=B(T)+f(x)+f(y)

正式證明

  • 由於不是按步驟歸納而是按規模歸納,所以第一步不是最重要的推理
  • n=2n=2時結論顯然
  • 假設n=kn=k時成立。對於一棵有n+1n+1個字符的二叉編碼樹,我們可以把兩片頻率最小的葉子a,ba,b放到最下面而不影響最優性
  • 將其合併成節點ss獲得樹T’,則可以根據貪心算法用T‘的葉子節點的權值構造最優二叉編碼樹T*
  • T’也是一棵最優二叉編碼樹,否則B(T’)>B(T*),兩邊同時加f(a),f(b),左邊變成B(T),右面是將a,ba,b填到ss下面得到的新樹,顯然T的最優性失效,矛盾
  • 所以把a,ba,b填到ss下面構成的新樹的平均編碼長度與最優編碼相等,它也是個最優編碼:使用貪心想法構成的最優編碼

套路總結

對於歸納問題規模型貪心,有以下套路:

  • 對於規模爲(n+1)(n+1)的問題,證明貪心操作所涉及的元素不會影響到最優性(如挪節點)
  • 合併,縮小問題規模爲TT',用歸納假設:規模爲nn時可用貪心構造TT^*
  • 證明TT'也是最優解,因爲TT'TT^*同規模,故展開後也同規模,故用貪心構造出的解對於(n+1)(n+1)規模也是最優解

講的很抽象,💊多練習。

最小生成樹:Prim

算法綜述

  • 將圖G的頂點分爲兩個集合:處理過的SS和未處理過的TST-S
  • 選擇連接SSTST-S的最短的邊ee,並將TST-S側的與ee相連的點加入到SS
  • 重複以上算法,直至TST-S爲空

證明思路

  • 與上一題不同,本題採用對貪心的步驟進行歸納,而非問題的規模
  • 證明的關鍵在於第一步:使用第一步的證明作爲後續子問題的歸納基礎
  • 通用思路:假設存在使第k步成立的最優方案,對於問題中剩下未處理的部分證明它必須用最優子問題的解法與前k步成立才能得到最終的最優方案
  • 利用歸納基礎:子問題的第一步可以用貪心算法,故構造了一個包含前k+1步貪心決策的最優決策。

證明實戰

  • 第一步必須是選擇權值最小的邊e1=(1,i)e_1=(1, i),否則若使用的是e1l,w(e1l)>w(e1)e_1^l, w(e_1^l)>w(e_1),在最終生成的樹TT中若加入e1e_1則生成含e1,e1le_1, e_1^l的圈,破除e1le_1^l後剩下的仍是一棵生成樹,但總長下降,與最優性矛盾
  • 假設存在最小生成樹TT包括前k步選擇的邊,構成了已處理點集SS和未處理點集VSV-S,根據最小生成樹的定義,TT的結構必須是SS中已經出現的樹+將SS看成一個大點後剩下點的生成樹合併的結果,運用第一步歸納假設即可證畢。

例:釣魚

題目描述

在一條水平路邊,有n(2n25)n(2\le n \le 25)個釣魚湖,從左到右編號爲1、2、3、……、n.佳佳有H(1H16)H(1 \le H \le 16)個小時的空餘時間,他希望用這些事件釣到儘量多的魚。他從湖1出發,向右走,有選擇的在第i+1i+1個湖邊停留一定的時間釣魚,最後在某一個湖邊結束釣魚。佳佳測出從第i個湖到第i+1i+1個湖需要走5Ti5*T_i分鐘的路,還測出在在第ii個湖邊停留,第一個5分鐘可以釣到魚FiF_i,以後再每釣5分鐘魚,魚量減少DiD_i,爲了簡化問題,佳佳假定沒有其他人釣魚,也不會有其他因素影響到他釣到期望數量的魚。請設計算法給出佳佳能釣到最多的魚的方案。


問題抽取

  • 變量太多了,行走時間,停留時間
  • 湖比較少,我們枚舉最後停留的湖,把行走時間變成常量
  • 問題中以5分鐘作爲基本單位,不妨把5去掉
  • 行走時間爲常量,那問題等價爲佳佳可以瞬間移動

貪心策略

  • 在第ii​分鐘瞬移到可以收穫最多魚的湖去抓魚,更新這個湖的抓魚量
  • 第一步正確性顯然,若存在最優解包含前kk​步選擇,則剩下的時間內也應是剩下時間內的最優選擇,故可用第一步構造處使用貪心算法的解與前kk​步成立
  • 證明較顯然故略去
  • 最後不要忘記將nn中情況合併

複雜度

  • 暴力枚舉各時刻可獲魚數最大值:O(Hn2)O(Hn^2)
  • 堆優化:O(Hnlogn)O(Hnlogn)

總結

感覺問題爲貪心解法時應注意控制可變量的個數,明確優化對象,方便思考


例:照亮的山景

題目描述

在一片山的上空,高度爲TT處有NN個處於不同水平位置的燈泡。如果山的邊界上某一點與燈i的連線不經過山上的其他點,我們稱燈i可以照亮該點。開儘量少的燈,使得整個山景都被照亮


優化對象選擇

  • 選擇電燈?
  • 區間是碎的,難以處理。(圖先欠着)

如果向下看

  • 所有的可行方案都照亮了所有的谷底
  • 所有照亮所有谷底的方案都是可行方案(光路是可逆的)
  • 能照亮一個谷底的燈必定是一個連續的區間(圖先欠着)

那我們直接以谷底優化對象好了


算法綜述

  • 對每一個谷底,預處理能將其照亮的所有燈泡區間
  • 選擇最少的燈泡,使得每個區間中至少有一個燈泡被選中了(貪心)

貪心決策(做有智商的莽夫)

  • 顯然的決策:如果區間II包含了區間JJ,那麼考慮區間II的決策是無用的,因爲必有一點在JJ中,II自然滿足
  • 只需討論所有部分重合和不重合的區間
  • 莽夫:最左側的區間是最危險的區間,那麼就考慮它,選它最右面的點,以保證能照亮更多與它重合的區間,把這些被照亮的區間刪去

證明

  • 以步數做歸納,顯然莽夫的思考過程就是我們的決策基礎
  • 若存在最優決策T包含前k步的決策,若再處理已選燈的區間是多餘的,去掉他們,應對後面的區間進行最優決策,而由歸納基礎得出存在以貪心決策開頭的方案使得其爲最優方案
  • 都是一個套路。。。
  • 時間複雜度:直接線性掃描,爲O(n)O(n)

例:潛泳比賽

題目描述

  • 有一支由NN人組成的潛水隊參與比賽,目標是全隊游到對岸。
  • 潛水需氧氣筒,整隊只有一個氧氣筒。
  • 氧氣筒可以兩人公用,但速度就是兩人中較慢者的速度。
  • 任意兩人可以一同潛泳。
  • 請設計最優方案,使得最後一名選手到達對岸的時間儘量早。

莽夫思路一

  • 總需要一個人來把氧氣筒送回來,而遊得再快的人也會被遊得慢的人拖累,不妨就讓遊得最快的人來回送氧氣筒

莽夫思路二

  • 如果讓最慢的兩個人一起過去,在對岸安排好送氧氣筒回來的人怎麼樣?
  • 把最快的兩個人先送過去,讓他們充當搬運工

請計算

  • 1、 2、 5、 6 、8、 9
  • 1、 2、 2、 2、 2、 2

如果合併這兩種思路

  • 這兩種思路的共同點,就是把最慢的兩個人送過去了,而對於不同的情況有不同的選擇
  • 若將所有人按照過河時間升序排序成a1,a2,...,aN{a_1, a_2, ..., a_N},那麼易知如果a1+aN12a2<0a_1+a_{N-1}-2a_2<0時用算法1,反之用算法2,我們就能最快地把最慢的兩個人送到對岸去
  • 這樣選擇研究的對象看起來和諧了一些

證明歸納基礎

  • 歸納基礎:將最慢的兩個人先用最快的方式送過去,不會影響總時間
  • 倘若存在最優策略不是這樣:最慢的兩個人要麼是一起過,要麼是拖累着別人過。
  • 這兩個人如果是一起過的,那就得有人回來送氧氣筒。如果對面有人的話肯定不是他們兩個中的一個回來送氧氣筒。如果不是a1a2a_1或a_2回來送,把a1,a2a_1,a_2調到前面去會更優。那不如把他們的過河順序都調到前面去
  • 如果這兩個人是分開過的,那麼還是用a1a_1去送氧氣筒最快,那麼爲什麼不把順序調到前面呢?
  • 完整證明思路與前面基本一樣,節省時間略去不提
  • 說不太清楚,有更好的思路請到我的萬年不更的博客下留言討論

時間複雜度

  • 只需線性掃描,O(n)O(n)結束

總結

!找好優化目標!

練:澆花問題

  • 有一長方形花壇,在於其較長邊平行的中軸線上安放了若干水龍頭,每個水龍頭能澆到草地的半徑是已知的。
  • 保證存在可以把所有草地都澆到的方案,請把其中一個選擇水龍頭最少的方案找出來
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章