一.递归与分治策略
思想:
分而治之; 大规模问题分解成可求解的小问题,把求的解再合并得到最后解;最优子结构:同性质的小问题;
算法框架:
divide-and-conquer(P){
if(|P|<=n0)
adhoc(P) //解决小规模问题;递归出口
divide P into smaller subinstances P1 P2 P3 ....
for(i=0;i<=k;i++)
yi=divide-and-conquer(Pi)
return merge(y1,y2,..)
}
经典例题:
- 递归方法正序打印数组元素
- 递归方法逆序打印数组元素
- 棋盘覆盖
- 最大最小问题
- 全排列问题
- 求数组的最大元素
二.动态规划
思想:
在分支算法的基础上解决子问题重复的问题
从最小子问题开始求解 自底向上
使用一个表格来保存已求出的解;在求子问题时,先查询表格,避免重复求解
算法框架:
int fib(int n){
int F[];//辅助表格
for(){
//第i次迭代循环
}
}
经典例题:
- 求解二项式系数 (n/m)=n!/[m!(n-m)!]
- 0/1背包问题
- 最长公共子序列
三.回溯法
思想:
以深度优先的方式搜素解空间树(空间树)
框架:
//递归回溯算法
void backtrack (int n){ //当前搜索层数
if(t>n) output(x);
else
for(i=f(n,t);i<g(n,t);i++){ //f(n,t)为起始孩子 g(n,t)为结束孩子
x[t]=h[i];//处于当前层数时 赋值
if (constraint(t) && bound(t))//用剪枝
backtrack(t+1)
}
}
经典例题:
- 0/1背包问题
- 旅行商问题
- n皇后问题
四.分支界限法
思想:
以广度优先或者最小耗费优先方式搜索解空间树
两种方法:
队列式 FIFO:先进先出的原则选取下一节点作为扩展节点
优先队列式: 选择优先级最高的节点成为当前的扩展结点
经典例题:
0/1背包问题
五.贪心算法
思想:
最优子结构性质+贪心选择性质
正确性证明:数学归纳法
框架:
经典例题:
- 活动安排问题
- 最优装载
- 单源最短路径问题