目录
1、递归
递归就是在函数内部自己调用自己
我们以递归的形式来实现斐波那契数列:0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89
#include<iostream>
using namespace std;
int fib(int n)
{
if(n == 1) return 0;
if(n == 2) return 1;
return fib(n - 1) + fib(n - 2);
}
对于每一个递归,都可以画出一颗递归搜索树
有n步,每一步都会分成两个分支,所以时间复杂度是O(2^n)
1.1 递归实现指数型枚举
这道题中,n是15,所以我们可以猜测时间复杂度是O(2^n)或O(n*2^n)
这道题我们可以采用DFS来做,对于DFS来说,搜索顺序非常重要。找到一个顺序,可以不重不漏地把每种方案找出。在这道题中,我们可以开一个数组,数组的1-n位,依次考虑每个数选或不选
对于位置1, 2, 3, ..., n,都有选和不选两种情况,所以是2^n。并且还要将每种方案输出,所以,时间复杂度是O(n*2^n)
#include<iostream>
using namespace std;
const int N = 20;
int n, a[N];
void dfs(int u)
{
if(u > n)
{
for(int i = 1;i <= n;i ++)
if(a[i] == 1)
cout << i << " ";
cout << endl;
return ;
}
a[u] = 2;
dfs(u + 1);
a[u] = 1;
dfs(u + 1);
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n;
dfs(1);
return 0;
}
1.2 递归实现排列型枚举
这道题也是采用DFS做。
顺序1:依次枚举每个数放到那个位置
顺序2:依次枚举每个位置放那个数
我们采用的是顺序2来做
#include<iostream>
using namespace std;
const int N = 15;
int n, a[N];
bool st[N];
void dfs(int u)
{
if(u > n)
{
for(int i = 1;i <= n;i ++)
cout << a[i] << " ";
cout << endl;
return ;
}
for(int i = 1;i <= n;i ++)
if(!st[i])
{
st[i] = true;
a[u] = i;
dfs(u + 1);
st[i] = false;
}
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n;
dfs(1);
return 0;
}
1.3 递归实现组合型枚举
排列是考虑顺序的,1 2 3和1 3 2是不一样的
组合是不考虑顺序的,1 2 3和1 3 2是一样的
所以,在递归实现组合型枚举时,需要规定一个顺序,这样在枚举时就可以保证不重复了,这里以升序为例。也就是说,对于1 2 3,1 3 2,2 1 3,2 3 1,3 1 2,3 2 1我们只枚举1 2 3即可
顺序:从前往后,依次枚举每个位置是几
为了有序,我们只需要时刻保持相邻两个位置的数有序即可
排列类型枚举需要一个bool类型的判重数组,而组合类型枚举不需要,因为只需要保证顺序即可
#include <iostream>
using namespace std;
const int N = 30;
int n, m;
int way[N];
void dfs(int u, int start) // u表示现在要填序列的第几位,start表示这一位可以从那个数开始填
{
if (u == m + 1)
{
for (int i = 1; i <= m; i ++ ) cout << way[i] << " ";
cout << endl;
return;
}
for (int i = start; i <= n; i ++ )
{
way[u] = i;
dfs(u + 1, i +