正如郭偉老師講的,遞歸怎麼講都不爲過。自覺得基本功紮實的我認爲本身對遞歸已經足夠了解,上了郭偉老師的課發現本身還只是只知其一;不知其二啊啊啊。因此仍是要謙虛,要及時認真的作筆記。ios
遞歸有一下幾個重要的做用:git
1替代多重循環(特別是在重數不肯定的時候)app
典型問題:求階乘,N皇后ide
2解決原本就是用遞歸形式定義的問題spa
典型問題:表達式求值,漢諾塔code
2.1表達式求值blog
遞歸定義的形式:遞歸
表達式 :項,項和項的加減運算ci
項:因子,因子和因子的乘除運算get
因子:'(’ 表達式 ')',整數
#include<cstdio> #include<cmath> #include<iostream> #include<algorithm> #include<vector> #include<string> #include<map> #define DEBUG(x) cout << #x << " = " << x << endl using namespace std; int exp_value(); int term_value(); int fact_value(); int exp_value() { int result=term_value(); bool more=true; while(more){ char c=cin.peek(); if(c=='+'||c=='-'){ cin.get(); int t=term_value(); if(c=='+')result+=t; else result-=t; } else more=false; } return result; } int term_value() { int result=fact_value(); bool more=true; while(more){ char c=cin.peek(); if(c=='/'||c=='*'){ cin.get(); int t=fact_value(); if(c=='/')result/=t; else result*=t; } else more=false; } return result; } int fact_value() { int result=0; char c=cin.peek(); if(c=='('){//c='c' cin.get(); result=exp_value(); cin.get(); } else { while(isdigit(c)){ result=result*10+c-'0'; cin.get(); c=cin.peek(); } } return result; } int main() { freopen("in.txt","r",stdin); printf("%d\n",exp_value()); return 0; }
2.2漢諾塔
#include<cstdio> #include<cmath> #include<iostream> #include<algorithm> #include<vector> #include<string> #include<map> #define DEBUG(x) cout << #x << " = " << x << endl using namespace std; ///漢諾塔問題 ///解決原本就是用遞歸形式定義的問題 void hanoi(int n,char src,char mid,char dst) { if(n==1){ cout<<src<<"->"<<dst<<endl; return; } hanoi(n-1,src,dst,mid); cout<<src<<"->"<<dst<<endl; hanoi(n-1,mid,src,dst); } int main() { // freopen("in.txt","r",stdin); hanoi(8,'A','B','C'); return 0; }
3將問題分解爲規模更小的子問題進行求
典型問題:上臺階,放蘋果,算24
3.1上臺階
仍是有點不太明白,爲何f(n)=f(n-1)+f(n-2)?
#include<iostream> #include<cstdio> using namespace std; int N; int stairs(int n) { if(n<0)return 0; if(n==0)return 1; return stairs(n-1)+stairs(n-2); } int main() { freopen("in.txt","r",stdin); while(cin>>N){ cout<<stairs(N)<<endl; } }
3.2放蘋果
實話說,我根本想不出來。。。
#include<cstdio> #include<cmath> #include<iostream> #include<algorithm> #include<vector> #include<string> #include<map> #define DEBUG(x) cout << #x << " = " << x << endl using namespace std; int apple(int m,int n) { if(n>m)return apple(m,m); if(m==0)return 1; if(n==0)return 0; return apple(m,n-1)+apple(m-n,n); } int main() { int t,m,n; freopen("in.txt","r",stdin); cin>>t; while(t--){ cin>>m>>n; cout<<apple(m,n); } return 0; }
3.3算24
比較經典,4個數算二十四,能夠先算兩個數,以後就是三個數算24,將問題分解爲規模更小的子問題進行求解,大概就是這個意思吧。
#include<cstdio> #include<cmath> #include<iostream> #include<algorithm> #include<vector> #include<string> #include<map> #define DEBUG(x) cout << #x << " = " << x << endl #define EPS 1e-6 using namespace std; double a[5]; bool isEqual(double a,double b) { return abs(a-b)<=EPS; } bool count24(double a[],int n) { int m=0; double b[5]; if(n==1) { // DEBUG(a[0]); if(isEqual(a[0],24.0)) return true; else return false; } for(int i=0; i<n-1; i++) { for(int j=i+1; j<n; j++) { for(int k=0; k<n; k++) { if(k!=i&&k!=j) { b[m++]=a[k]; } } double r; r=a[i]+a[j]; b[m]=r; if(count24(b,m+1)) return true; r=a[i]-a[j]; b[m]=r; if(count24(b,m+1)) return true; r=a[j]-a[i]; b[m]=r; if(count24(b,m+1)) return true; if(!isEqual(a[i],0)) { r=a[j]/a[i]; b[m]=r; if(count24(b,m+1)) return true; } if(!isEqual(a[j],0)) { r=a[i]/a[j]; b[m]=r; if(count24(b,m+1)) return true; } } } return false; } int main() { freopen("in.txt","r",stdin); for(int i=0;i<4;i++){ cin>>a[i]; } printf("%d\n",count24(a,4)); printf("%d\n",true); return 0; }