1. 程式人生 > 實用技巧 >學而思小猴程式設計演算法二階段課堂筆記

學而思小猴程式設計演算法二階段課堂筆記

(一) 遞迴Ⅰ

1、 知識點概要

先給大家講個故事:從前有座山,山裡有座廟,廟裡有個小和尚講故事:
         “從前有座山,山裡有座廟,廟裡有個小和尚講故事:”

         ““從前有座山,山裡有座廟,廟裡有個小和尚講故事:”從前有座山,山裡有座廟,廟裡有個小和尚講故事:” 

         ……

沒錯,你沒看錯,是個故事,如果繼續這麼講下去就是一直的在遞迴一個函式:

void 講故事(){

  cout << "從前有座山,山裡有座廟,廟裡有個小和尚講故事:";

  void(講故事);

}

沒錯,這就是最基本的遞迴函式,但是如果你不嫌煩的話,就看下去吧

這個函式裡的故事是毫無止境的,如果我們希望會有結束,就得加判斷

什麼時候結束,(例如:進行n次,講到有人輸入停止……)

這就講到了遞迴的重要要素:終止條件

遞迴的使用情況/條件:①重複地做某件事情,每次把做事情的次數減少,做這件事情的步驟一樣

           ②這件事情是有終止的時候

           ③不會像我舉的例子一樣煩  ̄へ ̄

這就是遞迴。

2、簡單練習熱熱身(´▽`)ノ

練習一:階乘(運算子號:"!")

階乘英文為fact

求n的階乘是多少

階乘:從1*2*3*……*n

寫成程式設計“語言”:n = n*(n-1)

終止條件:1的階乘是1

int fact(int n){
    if(n == 1){
        return 1;
    }
    return n*fact(n-1);
}

練習二:斐波那契數列

斐波那契數列英文為fibonacci,前幾項為1 1 2 3 5 8 13……,規律為第n個數為第n-1個數+第n-2個數

求斐波那契數列的第n項是多少

終止條件:第1項和第2項為1(一般題目都會告訴你,要麼你就得自己推導,但是這個是常識)

寫成程式設計“語言”:n = fibo(n-1)+fibo(n-2)

int fibo(int n){
    if(n == 1 || n == 2){
        return 1;
    }
    return n+fibo(n-1)+fibo(n-2);
}

練習三:求最大公約數問題

求a和b的最大公約數

方法:輾轉相除法

假設我們要求60和90的最大公約數

a

b

a%b
90 60 30
60 30 0

步驟如下:

1、確保a>b

2、把a%b算出來

3、如果a%b>0,把原本a的位置改為b,把b的位置改為a%b

4、再次計算a%b

5、如果a%b = 0,答案為b

int gcd(int a, int b){
    if(a % b == 0){
        return b;
    }
    return gcd(b,a%b);
}

3、重點難題

例一 計算組合數C(n,m) - 會

C(n,m)為n個數中選出m個數,不能重複選

考慮:第n個數選不選

①選 從n個數中選m-1個數

②不選 從n-1個數中選m個數

終止條件:C(n,0) = n和m相等 = 1

int C(int n, int m){
    if(m == 0 || n == m){
        return 1;
    }
    return C(n,m-1)+C(n-1,m);
}

例二 走格子 -

題目就不說了

可以從三個方向走,往上,往右,往右上。

m表示m列,n表示n行

到重點的位置有三個路線分別為

①從終點的下邊過來,下標為n-1,m

②從終點的左邊過來,下標為n,m-1

③從終點的左下方過來,下標為n-1,m-1

long long cnt(int n, int m){
    if(m == 0 || n == 0){
        return 1;
    }
    return cnt(n-1,m) + cnt(n,m-1) + cnt(n-1,m-1);
}

(二) 遞迴Ⅱ

重點難題:

1、天平

輸入5個砝碼的重量,輸出把所有砝碼都放到天平兩邊的都有多少種情況。

記錄砝碼重量的陣列:w[i]

自己定義的陣列:a[i]。a[i]如果為0,表示放左邊;如果為1,表示不放;如果為2,表示放右邊

再定義兩個變數:left:表示左邊的重量;right:表示右邊的重量

void search(int p){
    if(p > n){
        int left = 0, right = 0;
        for(int i = 1;i <= n;i++){
            if(a[i] == 0){
                left += w[i];
            }
            if(a[i] == 2){
                right += w[i];
            }
            if(left == right){
                cnt++;
            }
        }
        return;
    }
    for(a[p] = 0;a[p] <= 2;a[p]++){
        search(p+1);
    }
}

2、貨幣面值

有價值w[i]的現金c[i]張。

有多少種可能湊成m元。

void search(int p){
    if(p > n){//出口 
        int max = 0;
        for(int i = 1;i <= n;i++){
            max += w[i]*a[i];
        }
        if(max == m){
            cnt++;
        } 
        return;
    }
    for(a[p] = 0;a[p] <= c[p];a[p]++){//列舉a[p] 
        search(p+1);
    }
}