1. 程式人生 > >計算機演算法設計與分析一

計算機演算法設計與分析一

對待問題的思路:

1、如果問題能分解成子問題,考慮分治,並且能觀察最優子結構,考慮動態規劃,如果問題有貪心性質,考慮貪心

2、如果問題不能分或者不好分成問題,考慮逐步改進的方法,如線性規劃,非線性規劃,二次規劃,網路流等。

3、觀察解形式,x=[x1,x2,x3,x4...xn] xi=0/1,考慮列舉,智慧列舉,貪心等。

4、對於hard問題,考慮放鬆標準,如最優解->近似解,確定性演算法->隨機的演算法,最壞的情況下->正常的情況下。

例項一:

輸入:兩個數a,b(a>=b)

輸出:gcd(a,b)

分析:可以分解成子問題,如gcd(1949,101)->gcd(101,30)->gcd(30,11)->gcd(11,8)->gcd(8,3)->gcd(3,2)->gcd(2,1)->gcd(1,0),故採用分治演算法。

程式碼:

function Euclid(a,b):
    if b=0 then
        return a;
    end if
    return Euclid(b,a mod b);

例項二:

輸入:n個城市V={1,2,...,n},和一個距離矩陣D,dij(1<=i,j<=n)表示距離城市i到城市j。
輸出:最短的旅程,遊遍每個城市一次,回到最初的城市。

1、首先看能否分解成子問題

考慮M(S,e)表示最小距離,從城市1開始,旅行S中的每一個城市,並且最後到達e城市。

如下圖:

最短路徑可計算為:

min{d2,1 + M({3, 4}, 2),

d3,1 + M({2, 4}, 3),

d4,1 + M({2, 3}, 4)}

而如 M({2, 3},4)=min{d34 + M({2}, 3), d24 + M({3}, 2)}

而如M({2}, 3)=d12+d23

所以可以被分解成子問題

程式碼:

這裡e是指V中除去1的每個點

這裡i是指S中除去e的每個點

2、逐步改進策略

從一個粗略的完整的解決方案開始,然後逐步改進

這裡stopping(s)是指已經沒有neighbourhood可選了。

3、智慧列舉策略

方法一:通過邊

如上圖,a → b → c → d → e → a可以表示為 X = [1, 0, 0, 1, 1, 0, 0, 1, 0, 1]

我們可以遍歷所有的可能,如下圖:

但是這樣遍歷的可能性太多了,效率太低,我們可以考慮用剪枝的方法來提高效率

方法:

對於一個解X=????????,我們估計最短路程如下:

  • 對於每個城市,我們選擇最短的兩條邊
  • 這兩條邊的和小於等於2倍的最優路程。
  • 因此,我們可以給一個最低下界為1/2*(5+6+8+7+9)=17.5

如:對於X=10????????下界為1/2*(5+6+9+7+9)=18

所以,以此剪枝為

方法二:通過點

路程可以表示成點的序列,如X=[x1,x2,...,xn-1],xi為點,不失一般性,我們假定x1=a,且a,b在c之前出現。

於是我們可以這樣展開:

最後,結果如下: