基於歸納的算法設計

前言


算法中有很多會用到歸納的思想,如遞歸等算法的基礎都是歸納。今天來看看歸納的主要思想以及基於歸納的一些算法設計。


歸納

證明當n = 1時命題成立。
證明如果在n = k時命題成立,那麼可以推導出在n = k+1時命題也成立。(m代表任意自然數)
這種方法的原理在於:首先證明在某個起點值時命題成立,然後證明從一個值到下一個值的過程有效。當這兩點都已經證明,那麼任意值都可以通過反覆使用這個方法推導出來。

 

算法樣例

 

1、多項式求解

Pn(x) = anxn+an−1xn+…+a1x+a0

求Pn(x)

歸納假設:我們已求解出Pn-1(x) = an−1xn+…+a1x+a0

則Pn(x) = Pn-1(x) + an * x^n

Tn =  Tn + n + 1

int P(n){

    if(n == 0){

        return a[0];

    }

    else{

        P(n) = P(n - 1) + a[n] * x ^ n;

    }

}

 

增強歸納

同時歸納P(n)與x的n次方

int x[n]

int P(n){

    if(n == 0){

        return a[0];

    }

    else{

        x[n] = x[n - 1] * x;

        P(n) = P(n - 1) + a[n] * x[n];

    }

}

Tn = Tn-1 + 3

2n次乘法,n次加法

 

優化

Pn-1(x) = anxn −1+an−1xn+…+a1x

Pn(x) = P(n) * x + a[N - n]

 

Tn = Tn- 1 + 2

N 次乘法,n次加法

int P(n){

    if(n == 0){

        return a[0];

    }

    else{

        P(n) = x * P(n - 1) + a[N - n];

    }

}

 

2. 最大導出子圖

找G的最大導出子圖H, H 中所有頂點的度大於或等於k

 

歸納假設

頂點數少於n的,我們可以找到它的導出子圖

 

對於n的圖

遍歷所有點

若全都度>= k  則其就是最大的導出子圖

若有點小於k,刪去該點及所連邊,檢查剩下的圖

剩下的圖邊數少於n,根據歸納假設,可求得最大導出子圖

 

Graph(n){

    flag = 1;

    if(n = k){

        there is no biggest induced subgraph

    }

    for(every v in G){

        if(deg(v) < k){

            flag = 0;

            break;

        }

    }

    if(flag == 0){

        Graph(n - 1);

    }

    else{

        Graph is the biggest induced subgraph

    }

}

 

3. 一對一映射

集合A, f爲A到A的映射,A中找子集S使f在S上是one-to-one function

歸納假設

假設n-1規模的集合我們可以找到相應的S

對於n

遍歷所有元素

若每個元素都被映射到

則f爲one-to-one的

A便是S

 

若有元素沒有被映射到

則S中一定沒有這個元素

刪去這個元素

剩下n-1個,根據歸納

可求解

c[N] = {0, 0, ... }   //The in degree of element i
one_to_ont(){
    queue
    for(i = 0; i < n; i++){
        c[f(i)]++;
    }
    for(i = 0; i < n; i++){
        if(c[i] = 0){
            enque(i);
        }
    }
    while(!queue.empty()){
        v = dequeue();
        G = G - v;
        c[f(i)]--;
        if(c[f(i)] == 0){
            enque(f(i));
        }
    }
}
 

4. 社會名流

人與人關係有知道與不知道,若一個人被所有人知道,但自己不知道其他所有人,則他是社會名流。

 

歸納假設:

n-1規模的人中可以求解社會名流問題

隨便拿兩個人A和B

問A是否知道B

若知道,則A一定不是社會名流,刪除

若不知道,則B一點不是社會名流,刪除

還剩n-1個人

根據歸納假設,可以求解

 

不斷刪去,最後剩下的人有可能是,也可能不是

就是個社會名流的candidate

讓他與其他所有人每個問兩個問題,就可以確定其是不是

O(3(n-1))

know[i][j]   // i know j
 
socialStar(){
    i = 1;
    j = 2; 
    next = 3;
    for(k = 0; k < n - 1; k++){
        if(know[i][j]){
            i = next;
        }
        else{
            j = next;
        }
        next++;
    }
 
    if(i == next + 1){
        candidate = j
    }
    else{
        candidate = i;
    }
 
    for(i = 0; i < n; i++){
        check know[candidate][i]
        check know[i][candidate]
    }
}
 

5. 計算平衡因子

計算一棵樹(n個節點)上所有節點的平衡因子

 

歸納假設:已知節點數<n的樹上所有節點的平衡因子

 

發現這個歸納沒法求n

 

增強的歸納假設:已知節點數<n的樹上每個節點的平衡因子和高度

 

對於n個節點的樹

知道其根節點的左子樹與右子樹

根據歸納假設

知道左子樹高度

知道右子樹高度

可以求根的平衡因子

6. 最大連續子序列

給定序列 x1, x2, x3 … xn

求和最大的連續的子序列

 

歸納假設:已知規模<n的序列 的最大子序列

 

加入xn,沒法推得規模n的序列的最大子序列

 

增強的歸納假設:已知的規模<n的序列的最大子序列與後綴最大的子序列

 

加入xn

若xn加入使後綴序列和大於原先的最大子序列

則新序列最大後綴子序列加入xn,且最大子序列爲最大後綴子序列

 

若xn加入使後綴序列和還是小於原先的最大子序列,但>0

則新序列最大後綴子序列加入xn,且最大子序列仍爲原來的

 

若xn加入使後綴序列和<0

則新序列最大後綴子序列爲0,且最大子序列仍爲原來的

 

進化

A[i]爲以第i個元素結尾的最大子序列的和

 

I -> I + 1

若A[i] > 0, 則A[I + 1] = x[I + 1] + A[i]

Xi 加入其中

若A[i] < 0, 則A[I + 1] = x[I + 1]

 

最後遍歷A[i], 求最大值

總結

只要一個問題有基礎解,並能由更小的問題構造出來,那麼這個問題就可以用歸納來解決。基於歸納的算法還有很多很多,主要是明白了這種歸納的思想,然後就可以使用函數遞歸實現了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章