分治算法的基本思想是:
分(divide):递归求解子问题,即:分解+求解,将问题分解为k个方便求解的小问题。
为什么说是递归求解呢,这里可以看作将一个问题分2个子问题,如果2个子问题还是大,再继续分成4个子问题,直到分解到能方便求解的小问题。也就是说分治算法是含有2个以上的递归运算,只有一个递归的例程不能算做分治算法。
治(conquer):从子问题构建原问题的解。
对于分治,最长用到的复杂度分析情况为:
T(N) = aT(N/b) + O(N^k)
当a=b^k时, T(N)=O(N^k*logN)
比如,非常常见的二分法: T(N) = 2T(N/2) + O(N) ,此时a=2, b=2, k=1 即a=b^k,所以 该算法的复杂度为 O(NlogN)
从另一个角度,反向分析问题,如果我们希望得到一个O(NlogN)的算法,那么就需要保证附加工作为O(N),这是一个非常非常关键的利用分治算法解决问题的入手点!!!
而且这个复杂度也是大多数分治算法问题的情况。 当然还有另外两种>, < 情况,就参考书上的详细讲解吧。
下面以一个例子详细介绍如何应用分治算法。
最近点对问题:给定平面上的N个点,找出距离最近的两个点。
对于该问题,算法过程并不算复杂,但要想编程实现,需要克服不少细节问题。
首先应该实现Point类:
Point.h:
#include <iostream>
class Point
{
public :
Point( double x , double y);
double getx() const
{
return m_x;
}
double gety() const
{
return m_y;
}
friend std :: ostream & operator <<( std :: ostream & os , const Point & p);
private :
double m_x;
double m_y;
};
class Point
{
public :
Point( double x , double y);
double getx() const
{
return m_x;
}
double gety() const
{
return m_y;
}
friend std :: ostream & operator <<( std :: ostream & os , const Point & p);
private :
double m_x;
double m_y;
};
Point.cpp:
#include "Point.h"
Point :: Point( double x , double y) : m_x( x ), m_y( y)
{
}
std :: ostream & operator <<( std :: ostream & os , const Point & p)
{
os << "P(" <<p . getx() << "," <<p . gety() << ")";
return os;
}
Point :: Point( double x , double y) : m_x( x ), m_y( y)
{
}
std :: ostream & operator <<( std :: ostream & os , const Point & p)
{
os << "P(" <<p . getx() << "," <<p . gety() << ")";
return os;
}
这里有几点要注意:重载<<,友元函数的应用,初始化的位置。不多介绍了,代码很简单,上点心看看就好。
接下来,是解决该问题的具体过程:
1. 最简单的解法就是蛮力法:把每两个点的距离求出来,然后找出最小值即可。
虽然,该算法很简单,但编程实现时,从该笨方法起步会有一个很好的过渡,不至于编码难度过陡。
于是我们需要:计算两点距离的函数
Distance, 求最近点对函数
FindShortPair, 一组点
Point p
[]用以测试, 打印点函数
PrintPoints用于观察。
代码如下:
上面的代码完成了很多该问题算法的外围工作,最重要的是提供了测试环境。注意const的应用,double,int型的定义。
#include "Point.h"
#include <cmath>
double Distance( const Point & s , const Point & t)
{
double squarex = ( s . getx() - t . getx() ) * ( s . getx() - t . getx() );
double squarey = ( s . gety() - t . gety() ) * ( s . gety() - t . gety() );
return sqrt( squarex + squarey );
}
void FindShortPair( const Point * p , int num)
{ //can only find one of the shortest path
double distance = Distance(p [ 0 ], p [ 1 ]);
int start = 0;
int end = 1;
for ( int i = 0; i < num; i ++)
{
for (
#include <cmath>
double Distance( const Point & s , const Point & t)
{
double squarex = ( s . getx() - t . getx() ) * ( s . getx() - t . getx() );
double squarey = ( s . gety() - t . gety() ) * ( s . gety() - t . gety() );
return sqrt( squarex + squarey );
}
void FindShortPair( const Point * p , int num)
{ //can only find one of the shortest path
double distance = Distance(p [ 0 ], p [ 1 ]);
int start = 0;
int end = 1;
for ( int i = 0; i < num; i ++)
{
for (