简单的递归和递推
1.递归实现指数型枚举
题意:
从 1~n 这 n 个整数中随机选取任意多个,输出所有可能的选择方案。要求同一行内的数必须升序排列。
思路:
每个数有俩种情况,选中和不选中。由于要升序排列,递归可以实现,不管选与不选都是从小到大排列的。并且选与不选没有顺序之分。
代码:
#include <iostream>
#include <algorithm>
using namespace std;
const int N=20;
int st[N];
int n;
void dfs(int u)
{
if(u>n)
{
for(int i=1;i<=n;i++)
{
if(st[i]==1)
printf("%d ",i);
}
printf("\n");
return ;
}
//选
st[u]=1;
dfs(u+1);
st[u]=0;
//不选
st[u]=2;
dfs(u+1);
st[u]=0;
}
int main()
{
cin>>n;
dfs(1);
return 0;
}
2.递归实现排列型枚举
题意:
把 1~n 这 n 个整数排成一行后随机打乱顺序,输出所有可能的次序。
要求按照从小到大的顺序输出所有方案,每行1个。
思路:
这就是一个排列问题,每一个数都要输出,只是输出的顺序问题,很显然用递归来遍历比较好。输出结果按从小到大的顺序输出,所以从1开始遍历。这里要用一个数组来记录下顺序。
代码:
#include <iostream>
#include <algorithm>
using namespace std;
const int N=10;
int path[N];
bool st[N];
int n;
void dfs(int u)
{
if(u>n)
{
for(int i=1;i<=n;i++)
printf("%d ",path[i]);
printf("\n");
return ;
}
for(int i=1;i<=n;i++)
{
if(st[i]) continue;
st[i]=true;
path[u]=i;
dfs(u+1);
st[i]=false;
}
}
int main()
{
cin>>n;
dfs(1);
}
3.斐波那契数列的非递归实现
题意:
以下数列0 1 1 2 3 5 8 13 21 …被称为斐波纳契数列。
这个数列从第3项开始,每一项都等于前两项之和。
输入一个整数N,请你输出这个序列的前N项。
思路:
斐波那契的递归实现太耗费时间和空间,在比赛的时候基本都不能用,所以这里要非递归来实现,可以用数组进行预处理,一次循环就能得到所有的结果。
代码:
#include <iostream>
#include <algorithm>
using namespace std;
const int N=50;
int f[N];
int main()
{
f[1]==0;
f[2]=1;
for(int i=3;i<N;i++)
{
f[i]=f[i-1]+f[i-2];
}
int n;
cin>>n;
for(int i=1;i<=n;i++)
cout<<f[i]<<' ';
return 0;
}
4.递归实现组合型枚举
题意:
从 1~n 这 n 个整数中随机选出 m 个,输出所有可能的选择方案。
要求:
按照从小到大的顺序输出所有方案,每行1个。
首先,同一行内的数升序排列,相邻两个数用一个空格隔开。
其次,对于两个不同的行,对应下标的数一一比较,字典序较小的排在前面(例如1 3 5 7排在1 3 6 8前面)。
思路:
每个数同样有俩种选择,选和不选。不过递归的时候需要加一个参数,用来记录当前选的个数,只有选了m个才输出。
代码:
#include <iostream>
#include <algorithm>
using namespace std;
const int N=25;
bool st[N];
int path[N];
int n,m;
void dfs(int u,int cnt)
{
if(u>n && cnt<=m) return ;
if(cnt==m+1)
{
for(int i=1;i<=m;i++)
printf("%d ",path[i]);
printf("\n");
return ;
}
//选
st[u]=true;
path[cnt]=u;
dfs(u+1,cnt+1);
st[u]=false;
//不选
st[u]=true;
dfs(u+1,cnt);
st[u]=false;
}
int main()
{
cin>>n>>m;
dfs(1,1);
}