算法概論筆記 - 貪心法

采用步步逼近的方式構(gòu)造問題的解,其下一步的選擇總是在當(dāng)前看來收效最快和效果最明顯的那個。

使用前提: 驗證貪心模式的有效性

最小生成樹(minimum spanning tree)

輸入:無向圖G=(V, E); 邊權(quán)重w(e)
輸出:樹T=(V, E'),

其中![](http://latex.codecogs.com/svg.latex?E' \subseteq E), 使得權(quán)重![](http://latex.codecogs.com/svg.latex?weight(T) = \sum_{e \in E'} w_e)

樹的性質(zhì)
  1. 具有n個節(jié)點的樹的邊數(shù)為n-1
  2. 一個無向圖是樹,當(dāng)且僅當(dāng)任意兩個節(jié)點間僅存在唯一路徑
Kruskal算法

不斷地重復(fù)地選擇未被選中的邊中權(quán)重最輕而且不會形成環(huán)的一條。

procudure kruskal
for all u in V:
    makeset(u)
sort the edges E by weight
for all edges {u, v} in E, in increasing order of weight:
    if find(u) != find(v)
        add edge {u,v} to X
        union(u, v)
  • makeset(x): 創(chuàng)建一個僅包含x的獨立集合
  • find(x): x屬于哪個集合?
  • union(x, y): 合并包含x和y的集合
    共需要|V|次makeset + 2|E|次find + |V|-1次union操作

find操作不一定成功觸發(fā)union操作,因此最壞情況下會需要2|E|次

數(shù)據(jù)結(jié)構(gòu):有向樹
集合中的頂點對應(yīng)樹的節(jié)點,每個節(jié)點包含一個父指針,一級級指向樹根。樹根的父指針指向該元素自身。

有向樹

node

  1. p //父節(jié)點指針
  2. rank //該節(jié)點下懸掛的子樹高度
  • 方案一
    合并時讓較低的樹的根指向較高的樹的根(基于等級的合并)
  procedure makeset(x)
    p(x) = x
    rank(x) = 0
  procedure find(x)
    while(x != p(x))
        x = p(x)
    return x
  procedure union(x, y)
    rx = find(x), ry = find(y)
    if rx == ry return
    if rank(rx) > rank(ry)
        p(ry) = rx
    else if rank(rx) == rank(ry)
        p(rx) = ry
        rank(ry) += 1
    else
        p(rx) = ry
  • 方案二
    路徑壓縮: 循著一系列的父指針最終找到樹根后,改變所有這些父指針的目標(biāo),使其直接指向樹根
  procedure find(x)
    while(x != p(x))
        p(x) = find(p(x))
    return x

find中rank未進行更新,此時rank的含義無法解釋為子樹的高度。
此時有向樹的高度不會超過2。

  • 方案三
    我們可以發(fā)現(xiàn)find和union操作均只關(guān)心樹的頂層,是否可以直接使用樹高為2的有向樹呢?并在union()操作中,對于兩個樹高為2的有向樹,進行其中一棵的壓縮。

但仔細分析可以得出,此方案與方案二本質(zhì)相同,僅將find()操作總共所做的工作轉(zhuǎn)移到union()操作中。

方案序號 makeset find union 該部分效率
1 O(1) O(logn) O(logn) (V+E)logn
2 O(1) > O(1) > O(1) V+E

方案2如何平攤分析?TODO
總時間復(fù)雜度為T(sort)和T(find/union)中較大的那個

see java implement: greedy.mst.KruskalMST

Prim算法

算法中間階段的邊集X構(gòu)成一個子樹,該子樹頂點的集合表示為S。我們選擇S中頂點與S外頂點之間的最輕邊加入X,即以最小代價將所有原本不屬于S的頂點包含進來。

與Dijkstra的關(guān)系
偽代碼基本一致,區(qū)別體現(xiàn)在優(yōu)先隊列排序使用的鍵值

  • Prim: 鍵值為節(jié)點與集合S中頂點間的最輕邊的權(quán)重;
  • Dijkstra:鍵值為節(jié)點到起始點的完整路徑長度;

pseudocode如下:

procedure prim
for all u in V
    dist(u) = \infty
    pre(u) = nil

dist(s) = 0
PQ = makequeue(V) (using dist-values as keys)
while PQ is not empty
    u = deletemin(PQ)
    for all edges (u, v) in E
        if dist(v) > l(u, v)
            dist(v) = l(u, v)
            pre(v) = u
            decreasekey(PQ, v)

可以看到僅是dist(u)+l(u, v)變?yōu)?strong>l(u, v)

see java implement: greedy.mst.PrimMST

哈夫曼編碼
  • 編碼壓縮

壓縮比越高,隨機性越低,可預(yù)測性越好

  • 無前綴特性,任一個碼字都不應(yīng)該是其他碼字的前綴

無前綴編碼中每個字符對應(yīng)于樹中的一個葉節(jié)點

procedure Huffman(f)
Input: An array f[1...n] of frequencies
Output: An encoding tree with n leaves

let H be a priority queue of integers, ordered by f
for i = 1 to n: insert(H, i)
for k = n + 1 to 2n -1
    i = deletemin(H), j = deletemin(H)
    create a node numbered k with children i,j
    f[k] = f[i] + f[j]
    insert(H, k)

編碼輸出

call print(root, 1)

print(node, num) {
  if node is null return
  print node's code based on num
    :num to binary and then remove the head '1'
  print(node.left, 2*num)
  print(node.right, 2*num + 1)
}

see implement: greedy.Huffman

其他
Horn公式

問題描述
Horn公式中最基本的對象是取值為true或false的布爾變量,變量的知識通過蘊涵式、純否定兩類子句來表達。給定某個由以上兩類子句構(gòu)成的集合,我們需要判斷是否存在一個一致的解釋,即一組使得所有子句都滿足的變量(true/false)賦值,該解釋成為該Horn公式的一個可滿足賦值。

求解策略
從所有變量為false開始,依次將“只需且不得不”這樣做以使得某個蘊涵式滿足的變量置為true;一旦所有的蘊涵式都得到滿足,再回頭檢查是否所有否定子句仍然滿足。

集合覆蓋

問題描述


圖中的點表示一組城鎮(zhèn),需要建設(shè)一些新的學(xué)校。

具體要求:

  1. 所有的學(xué)校都必須建在城鎮(zhèn)上
  2. 從任意一個城鎮(zhèn)觸發(fā),都應(yīng)該可以在30英里的范圍到達其中的某一所學(xué)校
    那么,最少需要建多少所學(xué)校呢?

較優(yōu)解求解策略(貪心)
對每個城鎮(zhèn)x,令S(x)為在其30英里范圍內(nèi)的城鎮(zhèn)集合。
選取包含未被覆蓋元素的最大集合Si,不斷重復(fù),直到所有元素都被覆蓋。

貪心算法的逼近因子
貪心算法的解與實際的最優(yōu)解的規(guī)模之比可能因問題輸入的不同而不同,但是總小于ln(n)。我們稱這一最大比值為貪心算法的逼近因子。

寫在最后
  • 立個Flag,TODO will be done some day。
  • 渣代碼,且輕噴:worried:。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容