4.3.2 递归(很适合实现分治的思想):
递归的两个重要概念:
1.递归式:将原问题分解为若干个子问题的手段
2.递归边界:分解的尽头
1.递归实现n!
#include<iostream>
using namespace std;
int Fun(int n)
{
if(n==0 || n==1)
return 1;
else
return Fun(n-1)+Fun(n-2);
}
int main()
{
int a;
cin >> a;
cout << Fun(a);
}
2.递归实现Fibonacci函数:
3.递归实现全排列:
#include<iostream>
using namespace std;
const int maxn=100;
int n,p[maxn],HashTable[maxn]={false}; //散列数组HashTable的目的是为了保证没有重复的输出。p数组表示当前排列的元素
void generateP(int index) //index表示当前的位置
{
//递归边界:
if(index==n+1)
{
for(int i=1; i<=n; i++)
cout << p[i];
cout << endl;
return ;
}
//递归式子:
for(int x=1; x<=n; x++) //x表示遍历n中每一个数
{
if(HashTable[x]==false) //表示x在之前还没有被输出
{
HashTable[x]=true; //立即标记x已经被输出了
p[index]=x; //将x放到对应的位置
generateP(index+1); //赶紧进入下一个位置的数字输入
HashTable[x]=false; //当此函数调用回来时,要把之前的数字的标记全部清除以重新排列
}
}
}
int main()
{
n=4;
generateP(1);
}
4.n皇后问题:
1.什么是n皇后问题:
对于他妈的n皇后问题,就是在不同行不同列上去放皇后,并且保证皇后不在同一条对角线上。首先就是先保证不在同一行同一列,按照下面所讲的那个数字串,就是24135,,就是表示第1列中的皇后在第2行,第2列中的皇后在第4行,第3列中皇后在第1行…就相当于对这5个数进行全排列,如果说某一行上有两个皇后那么这5个数字就会有重复的显然不是全排列的结果,所以n皇后的问题就是先全排列再判断一条对角线上是否有2个及以上皇后,是的话即为abs(i-j)==abs(p[i]-p[j])
具体思路(暴力法):
int count=0;
void generateP(int index)
{
if(index==n+1)
{
bool flag=true; //先设置flag为true,
for(int i=1; i<=n; i++) //双层for判断是否有皇后在同一条对角线上,若是则设置flag为false
for(int j=1; j<=n; j++)
if(abs(i-j)==abs(p[i]-p[j]))
flag=false;
}
if(flag) //当双层for循环完后,如果flag仍为true,则count++
count++;
return ; //返回空
for(int x=1; x<=n; x++)
{
if(HashTable[x]==false) //这些都是全排列的代码,不变
{
p[index]=x;
HashTable[x]=true;
generateP(index+1);
HashTable[x]=false;
}
}
}
具体思路(回溯法):
回溯法定义:
int count=0;
void generateP(int index)
{
if(index==n+1)
{
count++;
return ;
}
for(int x=1; x<=n; x++)
{
if(HashTable[x]==false) //这个x为啥表示行?因为在全排列时这些数字就是表示皇后所在的行
{
//下面8行代码是在原来的全排列基础上新增的,作用:在决定每个位置放数字之前就进行一次判断
//先设置flag为true,然后让pre从1开始到index之前,判断有没有在同一个对角线上的
bool flag=true;
for(int pre=1; pre<index; pre++) //index表示要往当前位置插入数字,在插入之前进行判断
if(abs(index-pre)==abs(x-p[pre]))
{
flag=false;
break;
}
if(flag==true)
{
p[index]=x;
HashTable[x]=true;
generateP(index+1);
HashTable[x]=false;
}
}
}
}