分治算法 简析及举例
来源:互联网 发布:卡蒙刷q币软件 编辑:程序博客网 时间:2024/06/18 04:09
算法思想
1.分解:将一个难以直接解决的问题,分割成一些规模较小的相同问题,各个击破,分而治之。另外,处于平衡思想,子问题的规模大致相同时效率最优。
2.合并:将子问题的解决结果合并,得到该问题的解。
适用条件
1.缩小到一定规模可以解决(拿到问题先思考规模最小时的解决方法,再推而广之)
2.分解出的规模小、类型相同的子问题具有最优子结构性质。(递归思想的应用)
3.子问题的解可以合并为该问题的解。(若不满足这一点,则考虑贪心算法或动态规划算法)
4.子问题具有独立性(若不满足这一点,则算法会做很多重复工作,效率不高,最好用动态规划算法)
基本步骤
divide-and-conquer(P) { if ( | P | <= n0) adhoc(P); //解决小规模的问题 divide P into smaller subinstances P1,P2,...,Pk;//分解问题 for (i=1,i<=k,i++) yi=divide-and-conquer(Pi); //递归的解各子问题 return merge(y1,...,yk); //将各子问题的解合并为原问题的解 }
经典问题应用
1.二分搜索:给定升序排列的n个元素,要在n个元素中找出指定元素x。没一次执行while循环,问题规模少一半,且循环体内复杂度O(1),因此O(logn)。
类似的问题还有求数组的最大值。
//非递归实现int BinarySearch(Type a[], const Type& x, int l, int r){ while (r >= l){ int m = (l+r)/2; if (x == a[m]) return m; if (x < a[m]) r = m-1; else l = m+1; } return -1;}
2.合并排序:将待排序元素分成大小大致相同的2个子集合,分别对2个子集合进行排序,最终将排好序的子集合合并成为所要求的排好序的集合。 当n<=1,T(n)=(1);当n>1,T(n)=2T(n/2)+O(n);T(n)=O(nlogn)
void MergeSort(Type a[], int left, int right) { if (left<right) {//至少有2个元素 int i=(left+right)/2; //取中点 mergeSort(a, left, i); mergeSort(a, i+1, right); merge(a, b, left, i, right); //合并到数组b copy(a, b, left, right); //复制回数组a } }
3.棋盘覆盖问题:在一个2k×2k 个方格组成的棋盘中,恰有一个方格与其它方格不同,称该方格为一特殊方格,且称该棋盘为一特殊棋盘。在棋盘覆盖问题中,要用图示的4种不同形态的L型骨牌覆盖给定的特殊棋盘上除特殊方格以外的所有方格,且任何2个L型骨牌不得重叠覆盖。
解法:当k>0时,将2k×2k棋盘分割为4个2k-1×2k-1 子棋盘。
特殊方格必位于4个较小子棋盘之一中,其余3个子棋盘中无特殊方格。为了将这3个无特殊方格的子棋盘转化为特殊棋盘,可以用一个L型骨牌覆盖这3个较小棋盘的会合处,从而将原问题转化为4个较小规模的棋盘覆盖问题。递归地使用这种分割,直至棋盘简化为棋盘1×1。
void chessBoard(int tr, int tc, int dr, int dc, int size) { if (size == 1) return; int t = tile++, // L型骨牌号 int s = size/2; // 分割棋盘 // 覆盖左上角子棋盘 if (dr < tr + s && dc < tc + s) // 特殊方格在此棋盘中 chessBoard(tr, tc, dr, dc, s); else {// 此棋盘中无特殊方格 // 用 t 号L型骨牌覆盖右下角 board[tr + s - 1][tc + s - 1] = t; // 覆盖其余方格 chessBoard(tr, tc, tr+s-1, tc+s-1, s);} // 覆盖右上角子棋盘 if (dr < tr + s && dc >= tc + s)// 特殊方格在此棋盘中 chessBoard(tr, tc+s, dr, dc, s); else {// 此棋盘中无特殊方格 // 用 t 号L型骨牌覆盖左下角 board[tr + s - 1][tc + s] = t; // 覆盖其余方格 chessBoard(tr, tc+s, tr+s-1, tc+s, s);} // 覆盖左下角子棋盘 if (dr >= tr + s && dc < tc + s) // 特殊方格在此棋盘中 chessBoard(tr+s, tc, dr, dc, s); else {// 用 t 号L型骨牌覆盖右上角 board[tr + s][tc + s - 1] = t; // 覆盖其余方格 chessBoard(tr+s, tc, tr+s, tc+s-1, s);} // 覆盖右下角子棋盘 if (dr >= tr + s && dc >= tc + s) // 特殊方格在此棋盘中 chessBoard(tr+s, tc+s, dr, dc, s); else {// 用 t 号L型骨牌覆盖左上角 board[tr + s][tc + s] = t; // 覆盖其余方格 chessBoard(tr+s, tc+s, tr+s, tc+s, s);} }
4.循环赛日程表:设计一个满足以下要求的比赛日程表:
(1)每个选手必须与其他n-1个选手各赛一次;
(2)每个选手一天只能赛一次;
(3)循环赛一共进行n-1天。
解法:按分治策略,将所有的选手分为两半,n个选手的比赛日程表就可以通过为n/2个选手设计的比赛日程表来决定。递归地用对选手进行分割,直到只剩下2个选手时,比赛日程表的制定就变得很简单。这时只要让这2个选手进行比赛就可以了。
- 分治算法 简析及举例
- 排序算法及优化举例
- 常用STL容器及算法举例
- 常用STL容器及算法举例 .
- 常用STL容器及算法举例
- EM算法入门及简单应用举例
- 常用STL容器及算法举例
- 常用STL容器及算法举例
- 常用STL容器及算法举例
- 分治法,动态规划及贪心算法
- 【算法导论】分治法及归并排序
- 分治算法
- 分治算法
- 分治算法?
- 【算法】分治
- 【算法】分治
- 分治算法
- 分治算法
- Angular的第三方路由:ui-router
- 对html的Storage的理解与使用
- C语言基础学习笔记-善用标记变量(求素数)
- 解决Cannot change version of project facet Dynamic web module to 2.5
- python paranitm上传文件失败IO Permission
- 分治算法 简析及举例
- AR事务处理金额获取
- 配置Android交叉编译工具链环境变量
- scrapy-redis初次见面
- 1111DOM4J
- 后缀数组SA
- 求助:R语言sunburst函数
- C++读取txt数据为二维数组 将数据保存到txt文本中
- 数据库基础