一:前言
递归概念:在定义自身的同时又出现自身的直接或间接调用
注意:递归必须要有一个退出的条件!
二:利用递归实现的几种题型
题型1:利用递归实现排列型枚举
题目链接:https://www.luogu.com.cn/problem/P1706
思路讲解
开两个数组s[] 和 used[],s[i]代表每个位置上的数是多少,used[]代表这个数是否用过,在枚举数字从小到大进行枚举就OK啦~~
完整代码
//递归实现排列型枚举
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int n;
int s[15];
bool used[15];
void dfs(int u)
{
if(u>n)//结束条件,边界
{
for(int i = 1;i <= n;i++)
{
cout<<setw(5)<<s[i];//代表五个场宽
}
cout<<endl;
}
for(int i = 1;i <= n;i++)
{
if(!used[i])//数字i没有被用过
{
used[i] = true;//标记
s[u] = i;
dfs(u+1);
used[i] = false;//回溯--恢复原先的状态
s[u] = 0;
}
}
}
int main()
{
cin>>n;
dfs(1);
return 0;
}
题型2 :利用递归实现组合型枚举
题目链接:https://www.luogu.com.cn/problem/B3623
思路讲解
思路与上面一题差不多,定义两个数组used[] 和 vis[],思路与前面的一样,看了就可以理解的~~
完整代码
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int n,k;
int used[15];
bool vis[15];
void dfs(int step){
if(step==k){
for(int i = 1;i <= k;i++){
cout<<used[i]<<" ";
}
cout<<endl;
return; //到头了回溯--继续dfs搜索余下的情况
}
for(int i = 1;i <= n;i++){
if(vis[i]==false){ //等于
vis[i] = true; //赋值
used[step+1] = i;
dfs(step+1);
vis[i] = false; //步骤回溯
}
}
}
int main(){
memset(vis,false,sizeof(vis)); //memset(数组名,是/否,数组大小sizeof())
cin>>n>>k;;
dfs(0);
return 0;
}
这个题目与https://www.luogu.com.cn/problem/P1157 的思路一样,uu萌可以试一下(代码在下面,可以看看)
//递归实现组合型枚举
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int s[15];
int n,m;
void dfs(int u,int start)
{
if(u-1+n-start+1<m) return;//这个剪枝是在一个博客中看到的
//意思是当前选第u个数,前面已经选好u-1个数,从start到n共n - start + 1个数,所以(u-1) + (n-start+1)<m肯定不满足条件
if(u>m)
{
for(int i = 1;i <= m ;i++)
{
cout<<setw(3)<<s[i];
}
cout<<endl;
return;
}
for(int i= start;i <= n;i++)
{
s[u]=i;
dfs(u+1,i+1);
s[u] = 0;
}
}
int main()
{
cin>>n>>m;
dfs(1,1);
return 0;
}
题型3:利用递归实现指数型枚举
题目链接:https://www.acwing.com/problem/content/94/
思路讲解
定义一个数组s[],用来记录每个点的状态,其中0代表的是待考虑,1表示选择该数,2表示不选择该数
完整代码
//递归实现指数型枚举
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int n;
int s[15];//用来记录每个点的状态
// 0 表示待考虑,1 表示选择该数, 2 表示不选
void dfs(int x)
{
if(x==n)
{
for(int i = 0;i < n;i++)
{
if(s[i]==1)//表示选择该数
cout<<i+1<<" ";//输出
}
cout<<endl;
return;
}
s[x]=2;//第一个分支,不选
dfs(x+1);
s[x]=0;//回溯
s[x]=1;//第二个分支,选
dfs(x+1);
s[x]=0; //回溯
}
int main()
{
cin>>n;
dfs(0);
return 0;
}