基本算法-分治算法
来源:互联网 发布:ubuntu安装系统工具包 编辑:程序博客网 时间:2024/05/21 09:54
一、分治算法的基本思想是将一个规模大的问题按照一定的规则分解成多个小问题。这些小问题相互独立并且与原问题性质相同,求出小问题的解就可得到原问题的解。即一种分目标完成程序算法,简单问题可用二分法完成。
利用分治策略求解时,所需时间取决于分解后子问题的个数、子问题的规模大小等因素,而二分法,由于其划分的简单和均匀的特点,是经常采用的一种有效的方法,例如二分法检索。
二、使用场景:
分治法所能解决的问题一般具有以下几个特征:
1) 该问题的规模缩小到一定的程度就可以容易地解决
2) 该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质。
3) 利用该问题分解出的子问题的解可以合并为该问题的解;
4) 该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子子问题。
三、解题步骤:
(6)汉诺塔
五、具体实例:
1)二分搜索
二分搜索又叫做二分查找、折半查找,它是一种效率较高得查找方法。
二分搜索得要求:
线性表为有序表,并且要用向量作为表得存储结构。
二分搜索得基本思想:先确定待查找记录所在的范围,然后逐步缩小范围直至找到或找不到该记录位置。
二分查找步骤:
1、先确定中间位置:
middle = (left+right)/2;
2、将待查找得key值与data[middle].key值相比较。若相等,则查找成功并返回该位置,否则须确定新得查找区间,继续二分查找,具体方法如下:
- 如果data[middle].key大于key,由于data为有序线性表,可知data[middle...right].key均大于key,因此若表中存在关键字等于key得节点,则一定在位置middle左边的子表中。
- 反之, data[middle].key小于key, 因此若表中存在关键字等于key得节点,则一定在位置middle右边的子表中。下一次查找针对新得区域进行查找。
java代码实现:
1 public static void main(String[] args) { 2 int[] a = {1,2,3,4,5,6,7,8,9}; 3 int pos =bSearch(a, 0, a.length-1, 1); 4 System.out.println(pos); 5 } 6 7 8 public static int bSearch(int[] data,int left,int right,int key){ 9 //获取中间位置10 int middle = (left+right)/2;11 //比较key值如相等,返回当前位置,否则确认新的查找空间12 if(data[middle] == key){13 return middle;14 }else if(data[middle] >key){15 return bSearch(data, left, middle-1, key);16 }else{17 return bSearch(data, middle+1, right, key);18 }19 }
2)汉诺塔
在汉诺塔游戏中,有三个分别命名为A、B、C得塔座,几个大小各不相同,从小到大一次编号得圆盘,每个原盘中间有一个小孔。最初,所有得圆盘都在A塔座上,其中最大得圆盘在最下面,然后是第二大,以此类推.
游戏的目的是将所有的圆盘从塔座A移动到塔座B;塔座C用来防止临时圆盘,游戏的规则如下:
1、一次只能移动一个圆盘
2、任何时候都不能将一个较大的圆盘压在较小的圆盘上面.
3、除了第二条限制,任何塔座的最上面的圆盘都可以移动到其他塔座上.
汉诺塔问题解决思想:
在解决汉诺塔问题时,事实上,我们不是罪关心圆盘1开始应该挪到哪个塔座上,而是关心最下面的圆盘4.当然,我们不能直接移动圆盘4,但是圆盘4最终将从塔座A移动到塔座B.按照游戏规则,在移动圆盘4之前的情况一定如下图
我们仍将分析,如何将前三个圆盘从A移动到C,然后圆盘4从A移动到B,前三个圆盘从C再移动到B.
但是上面的步骤可以重复利用!例如将三个圆盘从A移动到C,那么应该先将前两个圆盘从A移动到B,然后将圆盘3从A移动到C,最后将前两个圆盘从B移动到C.
持续简化这个问题,最终我们将只需要处理一个圆盘从一个塔座移动到另一个塔座的问题.
java代码实现:
1 public class Moved { 2 private static int count = 1; 3 public static void main(String[] args) { 4 moved(4, "第一根柱子", "第二根柱子", "第三根柱子"); 5 } 6 7 /** 8 * 9 * @param i 圆盘数量10 * @param a 圆盘初始所在塔座11 * @param b 圆盘将要移动到的塔座12 * @param c 辅助圆盘移动的塔座13 */14 public static void moved(int i,String a,String b,String c){15 if(i == 1){16 disPaly(1, a, b);17 }else{18 //将i-1根圆盘由A移动到C19 moved(i-1, a, c, b);20 //将圆盘i 由A移动到B21 disPaly(i, a, b);22 //将i-1根圆盘由C移动到A23 moved(i-1,c,b,a);24 }25 }26 27 public static void disPaly(int i,String a,String b){28 System.out.println("第"+count+"步:移动第"+i+"个塔从"+a+"到"+b);29 count++;30 }31 }
运行结果:
1 第1步:移动第1个塔从第一根柱子到第三根柱子 2 第2步:移动第2个塔从第一根柱子到第二根柱子 3 第3步:移动第1个塔从第三根柱子到第二根柱子 4 第4步:移动第3个塔从第一根柱子到第三根柱子 5 第5步:移动第1个塔从第二根柱子到第一根柱子 6 第6步:移动第2个塔从第二根柱子到第三根柱子 7 第7步:移动第1个塔从第一根柱子到第三根柱子 8 第8步:移动第4个塔从第一根柱子到第二根柱子 9 第9步:移动第1个塔从第三根柱子到第二根柱子10 第10步:移动第2个塔从第三根柱子到第一根柱子11 第11步:移动第1个塔从第二根柱子到第一根柱子12 第12步:移动第3个塔从第三根柱子到第二根柱子13 第13步:移动第1个塔从第一根柱子到第三根柱子14 第14步:移动第2个塔从第一根柱子到第二根柱子15 第15步:移动第1个塔从第三根柱子到第二根柱子
3)求最值
在n个元素中找出最大元素和最小元素。我们可以把这n个元素放在一个数组中,用直接比较法求出。算法如下:
void maxmin1(int A[],int n,int *max,int *min)
{ int i;
*min=*max=A[0];
for(i=0;i <= n;i++)
{ if(A[i]> *max) *max= A[i];
if(A[i] < *min) *min= A[i];
}
}
上面这个算法需比较2(n-1)次。能否找到更好的算法呢?我们用分治策略来讨论。
把n个元素分成两组:
A1={A[1],...,A[int(n/2)]}和A2={A[INT(N/2)+1],...,A[N]}
分别求这两组的最大值和最小值,然后分别将这两组的最大值和最小值相比较,求出全部元素的最大值和最小值。如果A1和A2中的元素多于两个,则再用上述方法各分为两个子集。直至子集中元素至多两个元素为止。
例如有下面一组元素:-13,13,9,-5,7,23,0,15。用分治策略比较的算法如下:
void maxmin2(int A[],int i,int j,int *max,int *min)
/*A存放输入的数据,i,j存放数据的范围,初值为0,n-1,*max,*min 存放最大和最小值*/
{ int mid,max1,max2,min1,min2;
if (j==i) {最大和最小值为同一个数;return;}
if (j-1==i) {将两个数直接比较,求得最大和最小值;return;}
mid=(i+j)/2;
求i~mid之间的最大最小值分别为max1,min1;
求mid+1~j之间的最大最小值分别为max2,min2;
比较max1和max2,大的就是最大值;
比较min1和min2,小的就是最小值;
}
3)棋盘覆盖
4)找出伪币
六、总结
分治法的复杂性分析:
一个分治法将规模为n的问题分成k个规模为n/m的子问题去解。设分解阀值n0=1,且adhoc解规模为1的问题耗费1个单位时间。再设将原问题分解为k个子问题以及用merge将k个子问题的解合并为原问题的解需用f(n)个单位时间。用T(n)表示该分治法解规模为|P|=n的问题所需的计算时间,则有:
T(n)= k T(n/m)+f(n)
通过迭代法求得方程的解:
递归方程及其解只给出n等于m的方幂时T(n)的值,但是如果认为T(n)足够平滑,那么由n等于m的方幂时T(n)的值可以估计T(n)的增长速度。通常假定T(n)是单调上升的,从而当mi≤n<mi+1时,T(mi)≤T(n)<T(mi+1)。
运用分治策略解决的问题一般来说具有以下特点:
1、原问题可以分解为多个子问题
这些子问题与原问题相比,只是问题的规模有所降低,其结构和求解方法与原问题相同或相似。
2、原问题在分解过程中,递归地求解子问题
由于递归都必须有一个终止条件,因此,当分解后的子问题规模足够小时,应能够直接求解。
3、在求解并得到各个子问题的解后
应能够采用某种方式、方法合并或构造出原问题的解。
不难发现,在分治策略中,由于子问题与原问题在结构和解法上的相似性,用分治方法解决的问题,大都采用了递归的形式。在各种排序方法中,如归排序、堆排序、快速排序等,都存在有分治的思想。
- 基本算法-分治算法
- 基本算法之分治法
- HDU 4911 Inversion(基本算法-排序,基本算法-分治)
- 分治算法基本思想和典型案例
- 分治算法基本思想和典型例题
- 9种基本算法_分治
- 基本算法——第七单元 分治
- 基本的分治思想算法运用
- 分治算法
- 分治算法
- 分治算法?
- 【算法】分治
- 【算法】分治
- 分治算法
- 分治算法
- 分治算法
- 分治算法
- 分治算法
- leetcode 419. Battleships in a Board
- 单链表的C语言实现
- 【C++】【LeetCode】48. Rotate Image
- SpringMVC接受PUT和DELETE请求
- webpack-react
- 基本算法-分治算法
- 网络---NAT技术与代理服务器调研
- 23种设计模式-单例模式
- 最优化
- C
- 数据结构之循环队列和栈的应用
- 自动调用toString方法
- CRC校验原理
- 剑指offer——数组中的逆序对(复习归并排序)