分治的简明意思是:将大问题分成一个一个小问题,进行解决。
下面说说分治法解决问题的具体三个步骤(蕴含递归思想):
1.将原问题分解为一组子问题,每个子问题都与原问题类型相同,但是比原问题的规模小。
2.递归求解这些子问题。
3.将子问题的求解结果恰当合并,得到原问题的解。
以上三条能够运用分治法完全取决于第二和第三条,若不符合可以考虑动态规划和贪心法
根据分治法的分割原则,原问题应该分为多少个子问题才较适宜?各个子问题的规模应该怎样才为适当?这些问题很难予以肯定的回答。但人们从大量实践中发现,在用分治法设计算法时,最好使子问题的规模大致相同。换句话说,将一个问题分成大小相等的k个子问题的处理方法是行之有效的。许多问题可以取k=2。这种使子问题规模大致相等的做法是出自一种平衡(balancing)子问题的思想,它几乎总是比子问题规模不等的做法要好。
分治法的两种方式:
1自顶向下:就是上面说的解决步骤
2.自底向上:如果知道了最终直接可解的原子问题的全部情况,那么可采用由原子问题出发,向上递推的方法,由已有结论的小尺寸问题的解决,导致比它高一层次的同类问题的解决,最终使原问题彻底解决.这就是和递归向下方法对应的由底向上的分治方法的基本思路.
注:这个思想的关键是 分解
比较体现分治算法的具体例子:
快速排序,它的基本思想是:选择一个基准值,进行划分(比“基准值”小的元素居左边,比“基准值”大的元素居右边,基准值居中),然后对左右两半分别进行快速排序.这种划分不断进行,直到区域元素个数为1或0.这种尺寸为0或1的排序问题就是原子问题
另一个体现自底向上的思想的代码为:
- unsignedcountbits(unsignedx)
- {
- staticunsignedmask[]={
- 0x55555555,0x33333333,
- 0x0F0F0F0F,0x00FF00FF,
- 0x0000FFFF
- };
- for(unsignedi=0,shift=1;i<5;i++,shift<<=1)
- {
- x=(x&mask[i])+((x>>shift)&mask[i]);
- }
- returnx;
- }
以上代码请自行理解,以便你更好的理解分治算法。
..........................................................无敌分界线.......................................................
上面算法是求一个16进制数转换成2进制后一共含有几个1.也是最难想到的!
下面我们看看下面算法:
- #include<stdio.h>
- unsignedcountbits(unsignedx)
- {
- unsignedn=0;
- while(x)
- {
- x=x&(x-1);//和自己的上一个数进行与运算,每次都会关掉一个1
- ++n;//记录
- }
- returnn;
- }
- intmain(void)
- {
- intm;
- while(scanf("%d",&m)!=EOF)
- {
- printf("二进制中含有的1一共有%d/n",countbits(m));
- }
- }