首先来首歌曲来放松一下吧!
题目链接:93. 递归实现组合型枚举
题目背景:
递归实现,看完本篇你大概将知道递归转化为非递归方法!
题目描述
从 1~n 这 n 个整数中随机选出 m 个,输出所有可能的选择方案。
输入格式
两个整数 n,m ,在同一行用空格隔开。
输出格式
按照从小到大的顺序输出所有方案,每行1个。
首先,同一行内的数升序排列,相邻两个数用一个空格隔开。
其次,对于两个不同的行,对应下标的数一一比较,字典序较小的排在前面(例如1 3 5 7排在1 3 6 8前面)。
数据范围
n>0
0≤m≤n
n+(n−m)≤25
输入样例:
输出样例:
1 2 3 4 5 6 7 8 9 10
| 1 2 3 1 2 4 1 2 5 1 3 4 1 3 5 1 4 5 2 3 4 2 3 5 2 4 5 3 4 5
|
思考题:如果要求使用非递归方法,该怎么做呢?
题目分析:
题目要求:
解题思路:
一篇好理解的题解,点击这里!
题解:
题解一:最普通的递归:
不解释了!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| #include <iostream>
using namespace std;
const int N = 30; int n, m; int a[N]; bool visit[N];
void dfs(int k, int t, int m) { if(k == m) { for(int i = 0; i < k; i++) cout << a[i] << " "; cout << endl; return; } for(int i = t + 1; i <= n; i++) { if(!visit[i]) { a[k] = i; visit[i] = true; dfs(k + 1, i, m); visit[i] = false; } } }
int main() { cin >> n >> m; dfs(0, 0, m); return 0; }
|
题解二:这是错误的。。
题目要求最后要按字典序输出,如果用上次的二进制表示,结果没问题,但是顺序是乱的!没有规律的!
Go Out!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| #include <iostream>
using namespace std;
int n, m;
int main() { cin >> n >> m; for(int i = 0; i < 1 << n; i++) { int k = 0; for(int j = 0; j < n; j++) if(i >> j & 1) k++; if(k == m) { for(int t = 0; t < n; t++) if(i >> t & 1) cout << t + 1 << " "; cout << endl; } } return 0; }
|
题解三:yxc大神的递归,以及递归转非递归:
递归容易爆栈,有时候需要使用非递归!
递归仍然和上一题一样,稍微修改一下,多一个计数器,如果sum + 后面可以取到的数的最大位数 n - u, 还达不到 要求的m为,直接return;后面为了输出按照字典序,要换一下dfs选与不选的顺序,至于为什么(自己大脑稍微模拟一下过程即可)。
接下来就是,转化为非递归的做法,将递归的过程分为三部分,如图上所标示的:
pos 为0,为1,为2,三种状态!
使用State结构体存储状态,多一个pos来标识当前处于的状态:
将初状态鸭压入栈中:stk.push({0, 0, 0, 0});
进入while循环来判断三种状态:
- pos = 0,将递归的那一段写进去,改一下变量,将return改为continue,然后将当前状态改为1,压入栈中,将状态0的最后一句dfs也压入栈中。
- pos = 1,将当前状态改为2,压入栈中,将状态1的那一句dfs也压入栈中。
- pos = 2, 直接continue。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| #include <stack> #include <iostream>
using namespace std;
struct State { int pos, u, sum, state; };
int n, m;
void dfs(int u, int sum, int state) { 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); dfs(u + 1, sum, state); }
int main() { cin >> n >> m; stack<State> stk; stk.push({0, 0, 0, 0}); while(stk.size()) { State t = stk.top(); stk.pop(); if(t.pos == 0) { if(t.sum + n - t.u < m) continue; if(t.sum == m) { for(int i = 0; i < n; i++) if(t.state >> i & 1) cout << i + 1 << " "; cout << endl; continue; } t.pos = 1; stk.push(t); stk.push({0, t.u + 1, t.sum + 1, t.state | 1 << t.u}); } else if(t.pos == 1) { t.pos = 2; stk.push(t); stk.push({0, t.u + 1, t.sum, t.state}); } else continue; } return 0; }
|