算法初步——递归
分治
将原问题划分为若干个规模较小而结构与原问题相同或相似的子问题,然后分别解决这些子问题,最后合并子问题的解,即可得到原问题的解。
- 分解
- 解决:递归求解所有子问题
- 合并
递归
- 使用递归求解 n 的阶乘
// n! = 1*2*...*n int F(int n) { if(n==0) return 1; // 递归边界 else return F(n-1)*n; // 递归式 }
- 求 Fibonacci 数列 的第 n 项
// Fibonacci 数列 : F(0)=1,F(1)=1...F(n)=F(n-1)+F(n-2) int F(int n) { if(n==0 || n==1) return 1; // 递归边界 else return F(n-1) * F(n-2); // 递归式 }
- 全排列
- 思路:将将原问题分解为若干个子问题 :输出以 1 开头的全排列,输出以 2 开头的全排列.....
#include <cstdio> #include <string> #include <algorithm> #include <cmath> using namespace std; const int maxn = 11; // n 输入个数,P 当前排列,hashTable 记录整数 x 是否在 P 中 int n, P[maxn], hashTable[maxn] = {false}; // 现在处理排列的第 index 号位 void generateP(int index) { if(index == n+1) { // 递归边界,已经填满 n 位 for(int i=1; i<=n; ++i) { // 输出当前排列 printf("%d ", P[i]); } printf("\n"); return; } for(int x=1; x<=n; ++x) { // 枚举 1~n if(hashTable[x] == false) { // 若 x 还未填入,填入 P[index] P[index] = x; // 填入x hashTable[x] = true; // 标记 x 已填入 generateP(index+1); // 理排列的第 index+1 号位 hashTable[x] = false; // 还原状态 } } } int main() { n = 3; // 欲输出 1~3 的全排列 generateP(1); return 0; }
- 思路:将将原问题分解为若干个子问题 :输出以 1 开头的全排列,输出以 2 开头的全排列.....
- 回溯:n 皇后问题
- n 皇后问题是指:在一个 n*n 的国际象棋棋盘上放置 n 个皇后,使得这 n 个皇后两两均不在同一行、同一列、同一条对角线上,求合法的方案数
- 思路:回溯法,在全排列的基础上加上检查
#include <cstdio> #include <string> #include <algorithm> #include <cmath> using namespace std; const int maxn = 11; // n 输入个数,P 当前排列,hashTable 记录整数 x 是否在 P 中 int n, P[maxn], hashTable[maxn] = {false}, cnt=0; // 处理第 index 列的皇后 void generateP(int index) { if(index == n+1) { // 递归边界 cnt++; // 合法 return; } for(int x=1; x<=n; ++x) { // 遍历第 x 行 if(hashTable[x] == false) { // 第 x 行还没有皇后 bool flag = true; // 标记是否合法 for(int pre=1; pre<index; ++pre) { // 检查是否合法 if(abs(index-pre) == abs(x - P[pre])) { flag = false; // 与之前的皇后在一条对角线 break; } } if(flag) { // 合法 P[index] = x; // 令 index 列皇后的行数为 x hashTable[x] = true; // 标记 generateP(index+1); // 处理第 index+1 列的皇后 hashTable[x] = false; // 还原状态 } } } } int main() { n = 8; // 八皇后 generateP(1); printf("count = %d \n", cnt); // n=8 时 ,count = 92 return 0; }