1. 递推与递归的宏观描述
- 对于一个待求解的问题,我们由已知的某个小问题进而一步一步推向该问题的方法称为递推
- 递归正好与递推的方向相反,它是由大问题逐步分解为小问题,然后回溯到大问题进行解决的方法。
2. 递推与递归的简单应用
枚举形式 | 状态空间规模 | 一般遍历方式 |
多项式 | nk,k为常数 | 循环、递推 |
指数 | kn,k为常数 | 递归、位运算 |
排列 | n! | 递归、C++ next_permutation |
组合 | $inom{n}{m}$ | 递归+剪枝 |
3. 分治
把一个问题分解成若干个规模更小的同类子问题,对这些子问题求解,然后在回溯时通过他们推导出原问题的解。
4. 递归的机器实现
可以通过维护一个栈,将调用函数和返回函数的压栈出栈过程进行模拟,从而将递归实现循环。
相关练习:
1. 0301 递归实现指数型枚举
#include<iostream> #include<vector> using namespace std; vector<int> ans; int n, flag; void dfs(int dep, int idx){ if(dep == 0){ for(auto i : ans) cout<<i <<' '; cout<<endl; return ; } for(int i = idx; i <= n; ++i){ if(!(flag & (1 << i))){ flag += 1 << i; ans.push_back(i); dfs(dep-1, i+1); ans.pop_back(); flag -= 1 << i; //dfs(dep, i); } } } int main(){ cin>>n; for(int i = 0; i <= n; ++i) dfs(i, 1); return 0; }
2. 0302 递归/非递归实现组合型枚举
//递归型 #include<iostream> #include<vector> using namespace std; vector<int> ans; int n, m; void dfs(int x){ if(ans.size() == m){ for(auto i: ans) cout<<i<<' '; cout<<endl; return ; } for(int i = x; i <= n; ++i){ ans.push_back(i); dfs(i+1); ans.pop_back(); } } int main(){ cin>>n>>m; dfs(1); return 0; } //递推型 #include<iostream> #include<deque> using namespace std; struct info{ char x; deque<char> t; }; int n, m; deque<info> st; int main(){ cin>>n>>m; st.push_back({1, {}}); while(st.size()){ auto t = st.front(); st.pop_front(); if(n - t.x + 1 < m - t.t.size()) continue; for(int k = t.x; k <= n; ++k){ info l = t; if(t.t.size() < m){ l.t.push_back(k); l.x = k + 1; st.push_back(l); } } if(t.t.size() == m){ for(auto x: t.t) printf("%d ", x); cout<<endl; } } return 0; }
3. 0303 递归实现排列型枚举
#include<iostream> #include<vector> using namespace std; vector<int> ans; int n, flag; void dfs(int x){ if(x > n){ for(auto i: ans) cout<<i<<' '; cout<<endl; return; } for(int i = 1; i <= n; ++i ){ if(!(flag & (1 << i))){ ans.push_back(i); flag += 1 << i; dfs(x + 1); ans.pop_back(); flag -= 1 << i; } } } int main(){ cin>>n; dfs(1); return 0; }
4. 0201 费解的开关
#include<iostream> #include<vector> using namespace std; //#define _Debug int n; vector<string> record; const int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1}; void change(int x, int y, vector<string>& s){ char & t = s[x][y]; if(t == '1') t = '0'; else t = '1'; } void set_bit(int x, int y, vector<string>& t){ change(x, y, t); for(int i = 0; i < 4; ++i){ int nx = x + dx[i], ny = y + dy[i]; if(nx >= 0 && ny >= 0 && nx < 5 && ny < 5){ change(nx, ny, t); } } } int get_res(){ int minv = 0x3f3f3f3f; for(int i = 0; i < (1 << 5) -1; ++i){ vector<string> t = record; #ifdef _Debug cout<<i<<endl; cout<<t[1]<<endl; #endif int step = 0; for(int j = 0; j < 5; ++j){ if(i & (1 << j)){ ++step; set_bit(0, j, t); } } #ifdef _Debug cout<<t[1]<<endl; #endif for(int j = 0; j < 4; ++j){ for(int k = 0; k < 5; ++k) if(t[j][k] == '0') set_bit(j+1, k, t), ++step; } bool flag = true; for(int i = 0; i < 5; ++i){ if(t[4][i] == '0') flag = false; } if(flag) minv = min(minv, step); } return minv; } int main(){ cin>>n; while(n --){ string t; for(int i = 0; i < 5; ++i){ cin>>t; record.push_back(t); } int step = get_res(); if(step <= 6) cout<<step<<endl; else puts("-1"); record.clear(); } return 0; }
5. POJ1958 Strange Towers of Hanoi
#include<iostream> #include<cstring> using namespace std; const int N = 20; int dp3[N], dp4[N]; int main(){ memset(dp3, 0x3f, sizeof dp3), memset(dp4, 0x3f, sizeof dp4); dp3[0] = 0, dp4[0] = 0; for(int i = 1; i < 13; ++i) dp3[i] = dp3[i - 1] * 2 + 1; for(int i = 1; i < 13; ++i) for(int j = 0; j <= i; ++j) dp4[i] = min(dp4[i], dp4[j] * 2 + dp3[i - j]); for(int i = 1; i < 13; ++i) cout<<dp4[i]<<endl; return 0; }