什麼是遞歸呢?遞歸就是反覆調用自身函數,但是每次把問題範圍縮小,直到範圍縮小到可以直接得到邊界數據的結果,最後再在返回的路上得到相應的解。
遞歸的邏輯中有兩個重要的概念:
- 遞歸邊界,遞歸邊界用來返回最簡單底層的結果
- 遞歸式,也叫遞歸調用,遞歸式用來減少數據規模並向下一層遞歸
以下經典例子,求n!
#include<stdio.h>
int F(int n)
{
if(n==1)
return 1;
else return F(n-1)*n;
}
int main()
{
int n;
scanf("%d",&n);
printf("%d\n",F(n));
return 0;
}
求解斐波那契數列的第n項
#include<stdio.h>
int F(int n)
{
if(n==0||n==1)
return 1;
else
return F(n-1)+F(n-2);
}
int main()
{
int n;
scanf("%d",&n);
printf("%d\n,F(n));
return 0;
}
全排列問題,即把1到這n個整數按某個順序擺放的結果稱爲這n個整數的一個排列,而全排列指n個整數能形成的所有排列
#include<cstdio>
const int maxn=15;
//D爲當前排列,hashtable記錄整數x是否已經在D中
int n,D[maxn],hashtable[maxn]={false};
//當前處理排序的第index位
void generateD(int index)
{
if(index==n+1)//遞歸邊界,已經處理完排列的n+1位
{
for(int i=1;i<n;i++)
{
printf("%d",D[i]);//輸出當前排列
}
printf("\n");
return;
}
for(int x=1;x<=n;x++)//枚舉1到n,試圖將x填入D[index]
{
if(hashtable[x]==false)//如果x不在D[0]到D[index-1]中
{
D[index]=x;//令D的第index位爲x,即把x加入當前排列
hashtable[x]=true;//記錄x已在D中
generateD(index+1);//處理已經排序結束的第index+1位
hashtable[x]=false;//已經處理完D[index]爲x的子問題,還原狀態
}
}
}
int main()
{
n=13;
generateD(1);
return 0;
}
n皇后問題,n皇后問題是在一個n*n的國際象棋棋盤上放置n個皇后,使得這n個皇后兩兩均不在同一行,同一列,同一條對角線上,求合法的方案數。
若採用組合數的方式來枚舉每一種情況(即從n^2個位置中選擇n個位置),n=8時就是54502232次枚舉,當n很大時計算機可能無法算出,換個思路,考慮到每行只能放置一個皇后,每列也是,那麼如果將n列皇后所在的行號依次寫出,即爲1到n的一個排列,那麼只需要枚舉1到n的所有排列,然後統計其中合法的方案即可(某種意義上與數獨有相關性)
暴力法
#include<cstdio>
#include<cmath>
const int maxn=50;
int count=0,n,D[maxn],hashtable[maxn]={false};
void generateD(int index)
{
if(index==n+1)
{
bool flag=true;//表示當前排列爲合法的一個方案
for(int i=1;i<n;i++)//遍歷任意兩個皇后
{
for(int j=i+1;j<=n;j++)
{
if(abs(i-j)==abs(D[i]-D[j]))//如果在一條對角線上
{
flag=false;
}
}
}
if(flag)
count++;//若當前方案合法,令count加一
return;
}
for(int x=1;x<=n;x++)
{
if(hashtable[x]==false)
{
D[index]=x;
hashtable[x]=true;
generateD(index+1);
hashtable[x]=false;
}
}
}
int main()
{
n=9;
generateD(1);
printf("%d",count);
return 0;
}