遞迴

一個函式重複呼叫自己,就是遞迴

一個函式重複呼叫自己,就是遞迴

#include<bits/stdc++.h>
using namespace std;

void g(int a){
    if(a==0) return;
    cout<<"haha"<<endl;
    return g(a-1);
}
int main(){
    g(4);
}

有什麼用?

有什麼用?

枚舉、DFS、線段樹、分治................

有什麼用?

枚舉、DFS、線段樹、分治................

幾乎什麼都會用到

例題 : 費氏數列

是什麼應該不用我多說

 1    1    2    3    5    8    13   21    34

是什麼應該不用我多說

 0     1    1    2    3    5    8    13   21    34

f(i) = 費事數列第i項

f(i) = f(i-1) + f(i-2)

試著用遞迴做出求費事數列第 n 項

試著用遞迴做出求費事數列第 n 項

f(i) = f(i-1) + f(i-2)

f(1) = 0

f(2) = 1

#include<bits/stdc++.h>
using namespace std;

int f(int x){
    if(x == 1) return 0;
    if(x == 2) return 1;
    return f(x-1)+f(x-2);
}
int main(){
	int n; cin>>n;
    cout<<f(n)<<endl;
}

如果我要求第45項 ...

如果我要求第45項 ...

居然卡住了

如果我要求第45項 ...

居然卡住了

n

n-1

n-2

n-4

n-3

n-3

n-2

.......

1   or  2

如果我要求第45項 ...

居然卡住了

n

n-1

n-2

n-4

n-3

n-3

n-2

.......

1   or  2

好多重複的東西 !

把重複的東西記起來

n

n-1

n-2

n-4

n-3

n-3

n-2

n-3

n-4

把重複的東西記起來

n

n-1

n-2

n-4

n-3

n-3

n-2

n-3

n-4

#include<bits/stdc++.h>
using namespace std;
#define int long long

int tmp[10000000];
int f(int x){
    if(x == 1) return 0;
    if(x == 2) return 1;
    if(tmp[x] != 0) return tmp[x];
    return tmp[x] = f(x-1)+f(x-2);
}
main(){
    cout<<f(70)<<endl;
}

例題 : 河內塔

規則 :

給定一開始A上的盤子數

求最少步驟數

求步驟(幾號盤子從哪裡搬到哪)

遞迴 -> 拆解問題

怎麼拆?

遞迴 -> 拆解問題

怎麼拆?

先幫盤子由上往下編號1~n

假設現在有 n 個盤子在 A

怎麼移 ?

假設現在有 n 個盤子在 A

怎麼移 ?

我可以先把 1~n-1 共n-1個盤子移到B

假設現在有 n 個盤子在 A

怎麼移 ?

我可以先把 1~n-1 共n-1個盤子移到B

再把n號盤從A移到C

假設現在有 n 個盤子在 A

怎麼移 ?

我可以先把 1~n-1 共n-1個盤子移到B

再把n號盤從A移到C

最後把1~n-1號盤從 B 移到 C

因此假設 f(x) 是 n = x 的答案

f(x) = f(x-1) + f(1) + f(x-1)

f(x) = f(x-1) +1+ f(x-1)

f(x) = f(x-1)*2+1

#include<bits/stdc++.h>
using namespace std;
#define int long long

int tmp[1000000];
int f(int x){
    if(tmp[x] != 0) return tmp[x];
    if(x == 1) return tmp[x] = 1;
    return tmp[x] = 2*f(x-1) + 1;
}
main(){
    int n; cin>>n;
    cout<<f(n)<<endl;
}

最少布數好了,那實際步驟呢 ?

最少布數好了,那實際步驟呢 ?

!!! 注意到

把 f(x) 拆成 f(x-1) 後,就變成 n = x-1問題的了

不用管n號盤

是兩件獨立的事情

最少布數好了,那實際步驟呢 ?

!!! 注意到

把 f(x) 拆成 f(x-1) 後,就變成 n = x-1問題的了

不用管n號盤

是兩件獨立的事情

設 f(x,A,C,B) 

把 x 個盤子從 A 移到 C,藉由 B

設 f(x,A,C,B) 

把 x 個盤子從 A 移到 C,藉由 B

這裡的ABC只是代號 !!

f(x,A,C,B) = f(x-1,A,B,C) + 把n號從A移到C + f(x-1,B,C,A)

 把n號從A移到C、x = 1

是真正我要動的步驟

#include<bits/stdc++.h>
using namespace std;
#define int long long

void f(int x,char A,char C,char B){
    if(x==1){
        cout<<"Move ring 1 from "<<A<<" to "<<C<<endl;
        return;
    }
    f(x-1,A,B,C);
    cout<<"Move ring "<<x<<" from "<<A<<" to "<<C<<endl;
    f(x-1,B,C,A);
}
main(){
    int n; cin>>n;
    f(n,'A','C','B');
}

遞迴

By maxbrucelen