一、概述
分治算法说白了就是把一个大型问题转化为小问题逐个解决。
个人感觉和分治算法含有递归的意味。
一般步骤:
(1)分解,将要解决的问题划分成若干规模较小的同类问题;
(2)求解,当子问题划分得足够小时,用较简单的方法解决;
(3)合并,按原问题的要求,将子问题的解逐层合并构成原问题的解。
总之,分治可以产生贪心,二分,线段树等问题。
说实话,分治算法是一种思想,没有什么特定的代码框架。
接下来我们来看一些使用分治算法的经典问题。
二、二分找数
二分是一种求极值的算法,通常已知答案的取值范围,枚举范围中点,并逐步缩小范围。
举个例子:员工小C和志熊在一起快乐吃鸡,两人决赛圈想当伏地魔而不专心,玩起了猜子弹游戏。
当然,小C是个新手,而系统自动拾取子弹,所以自己从来不关心自己有多少子弹(只是看有拾取标识就点);志熊是个黄金,知道系统认为同一种捡200发就够了,那志熊每一次猜测的最优解是什么呢?
自然是先猜(1+200)/2=100发了,这样有可能一次猜中(几率很小,欧吃矛),但更多的好处在于可以立刻缩减最非时的最大范围。于是这样每次猜正中间,很快便能找到答案,而且思维比较规范,不会乱。
这就是分治算法的体现。
代码主要结构如下,各有各的写法:
int search(int goal);
{
int l=1,r=n;
while(l<=r)
{
int mid=(l+r)/2;
if(a[mid]==goal) return mid;
else if(a[mid]>goal) r=mid-1;
else l=mid+1;
}
return -1;
}
三、快排
已经厌倦 algorithm 中的sort的OIER以及与时间赛跑的dalao可以试试手打快排。
快排是当前对于部分问题来说,确实是所有排序方法中最优解之一。
代码贴一下吧:
void qsort(int l,int r)
{
int i,j,mid,p;
i=l;j=r;
mid=a[(l+r)/2];
do
{
while (a[i]<mid) i++;
while (a[j]>mid) j--;
if (o<=j)
{
p=a[i];a[i]=a[j];a[j]=p;
i++;j--;
}
}while(i<=j);
if (l<j) qsort(l,j);
if (i<r) qsort(i,r);
}
四、总结
这个思想比较巧妙,大家可以写一些这几道题,比较有趣,分治思想也比较明显。
[HNOI2006]鬼谷子的钱袋
洛谷 P1010 幂次方
洛谷 P1908 逆序对