指数型枚举
体积 - 小志61314 - 博客园 (cnblogs.com)
每一个数可以分为选和不选的两种情况,这也是一个状态空间了,总共两种情况,可以依次枚举每个数选还是不选,正好做到不重不漏。
首先找到问题的边界,由原问题出发到边界,一层层扩展
每个数选还是不选
一开始每个数都不选,然后到边界每个数都需要经历过选还是不选,这是一个大类,在一个数选择了基础上,下面的依次是选还是不选,(这个地方看代码,下面的递归开始的时候,自然进入到不选的那个递归,直到边界)然后回溯就开始依次选上了,不要忘记还原现场
下面看代码吧
#include<iostream>
#include<vector>
using namespace std;
vector<int> v;
int n;
void dfs(int u)
{
if(u==n+1)
{
for(int i=0;i<v.size();i++)
cout<<v[i]<<" ";
cout<<endl;
return ;
}
dfs(u+1);
v.push_back(u);
dfs(u+1);
v.pop_back();
}
int main(){
cin>>n;
dfs(1);
return 0;
}
组合型递归:
谷仓的安保 - 小志61314 - 博客园 (cnblogs.com) 这个是组合型例题
数的划分 - 小志61314 - 博客园 (cnblogs.com)类似的剪枝方法
可以在指数型基础上加入剪枝,因为组合型要求顺序不变,刚好指数型是每一个分支,没有重复的,再在剪枝的基础上加入m变量就可以了
#include<iostream>
#include<vector>
using namespace std;
int n,m;
vector<int> v;
void dfs(int u,int cnt)
{
if(v.size()>m||v.size()+n-u+1<m) return ;
if(u==n+1&&cnt==m)
{
for(int i=0;i<v.size();i++)
cout<<v[i]<<" ";
cout<<endl;
return ;
}
cnt++;
v.push_back(u);
dfs(u+1,cnt);
cnt--;
v.pop_back();
dfs(u+1,cnt);
}
int main(){
cin>>n>>m;
dfs(1,0);
return 0;
}
还有一种就是完全不同的搜索方法
按照字典序从小到大排列且没有重复,直接定义一个start,保证后面的数全部比start大即可
#include<iostream>
using namespace std;
int n,m;
const int N=50;
int p[N];
void dfs(int u,int start)//第二个保证了是以start开始,以确保不会重复
{
if(u==m+1)
{
for(int i=1;i<=m;i++)
cout<<p[i]<<" ";
cout<<endl;
return ;
}
for(int i=start;i<=n;i++)
{
p[u]=i;
dfs(u+1,i+1);
}
}
int main(){
cin>>n>>m;
dfs(1,1);
return 0;
}
排列型递归:
带分数 - 小志61314 - 博客园 (cnblogs.com) 排列型的应用,不过用到了STL的函数(可以不用手搓长代码了QAQ)
#include<iostream>
using namespace std;
const int N=50;
int n;
int p[N];
bool st[N];//判重,不能有重复
void dfs(int u)
{
if(u==n+1)
{
for(int i=1;i<=n;i++)
cout<<p[i]<<" ";
cout<<endl;
return ;
}
for(int i=1;i<=n;i++)
{
if(!st[i])
{
st[i]=true;//填
p[u]=i;
dfs(u+1);//下一层再填数
st[i]=false;//回溯,还原现场
}
}
}
int main(){
cin>>n;
dfs(1);
return 0;
}