来个例题
唔,就用这题来讲一下吧
计算机实现递归也不是真的递归,是用栈来存储每一个状态,我们这里也是这样,就直接模拟一下这个操作,递归是分叉的,栈是个串的,就是要记录好,遍历到哪个分支的那一部分了
就是看一下,这个函数,需要记录哪些状态才能保证我们回溯的时候,能继续进行,这里很简单,就是看一下,从哪里进去的就可以,就是记录当前递归函数执行到哪一步了。每一次执行到递归之前,我们先把当前状态放进去表示我们之后要从这里继续执行,然后递归执行
详见代码,代码中有详细的注释
#include <iostream>
#include <stack>
using namespace std;
int n, m;
struct State
{
int pos;//已经运行到程序的哪一步了,对应下面0, 1,2
//其他的就是记录一下dfs里面的应该记录的几个状态
int u, sum, state; //枚举到了哪一个,选了多少个,当前选了哪些数(是一个二进制数)
};
void dfs(int u, int sum, int state)
{
//以递归为分段,这里是第0部分,就是从这里进来的
//0:
if(sum + n - u < m) return;
if(sum == m)
{
for(int i = 0; i < n; i ++)
if(state >> i & 1)
cout<<i+1<<' ';
cout<<endl;
return;
}
dfs(u+1, sum+1, state|1<<u);
//子函数递归结束
//1:
dfs(u+1, sum, state);
//2:
//第二次递归也结束了
}
int main()
{
cin>>n>>m;
// dfs(0, 0, 0);
stack<State> stk;
stk.push({0, 0, 0, 0});//初始状态
//第一个0表示从0,哪个地方进去,其他的三个0照抄dfs
while(stk.size()) //栈不空就一直循环
{
auto a = stk.top();
stk.pop();
if(a.pos == 0)//第一种是从头开始进来怎么办
{
if(a.sum + n - a.u < m) continue;
if(a.sum == m)
{
for(int i = 0; i < n; i ++)
if(a.state >> i & 1)
cout << i + 1 << ' ';
cout << endl;
continue;
}
a.pos = 1;
stk.push(a);
stk.push({0, a.u+1, a.sum+1, a.state | 1 << a.u});
}
else if(a.pos == 1)//第二种是第一次递归结束了,回溯回来了怎么办
{
a.pos = 2;
stk.push(a);
stk.push({0, a.u+1, a.sum, a.state});
}
else continue;
}
return 0;
}