初學算法-分治法求平面上最近點對(Closest Pair)-HDU 1007

    原本這個算法在筆者電腦裏無人問津過一段時間了,但今天正好作HDU 1007見到了這個問題,今天就來把代碼分享出來吧!ios

    咱們首先將全部點按照座標x排序一下,再作一條直線l看成「分割線」,方便咱們遞歸。
算法

    而後,咱們就能夠把這些點按照x軸的座標分爲左半部分和右半部分。那麼最短距離必定在左半部分、右半部分、跨越左右的點對中的一個。 
ide

    那麼你可能會有疑問了:原本最近點對也必定在這三個區域內,這不仍是至關於什麼都沒幹嘛?
spa

    還真不是。咱們能夠假設經過遞歸獲得了左邊最小距離爲d1,右邊最小距離爲d2,令δ = min(d1,d2)code









    如圖所示,若是跨越左右的點對多是最短距離,那麼它也必然比δ小。而在以l爲中心、最大距離爲2δ的區域中,最多有O(n)個如圖所示的矩形。另外,能夠證實對於每一個矩形區域,最多嘗試8個點對必定能找到最短距離(算法導論第33.4節有詳細的證實,這裏再也不贅述)。排序

    所以,咱們能夠寫出遞歸式:T(n)=2T(n/2)+O(n),能夠用主項定理(master method)解得時間複雜度T(n)=O(nlogn)。加上排序一次的時間O(nlogn),所以整個算法的運行時間T(n)' = T(n)+O(nlogn) = O(nlogn)。遞歸

    下面,經過這個算法,咱們就能夠寫出一份代碼來:ci

/**
 * Find closest distance in N points.
 * Time cost: O(nlogn)
 * Author: Zheng Chen / Arclabs001
 * Copyright 2015 Xi'an University of Posts & Telecommunications
 */

/**
 * Algorithm:
 * First of all, sort the points in ascending order by x.
 * Divide the array into 2 parts, and find the smallest distance within two parts.
 * Let min as the smaller one, and find the smallest split distance.
 */
#include <iostream>
#include <algorithm>
#include <cmath>
#define INF 0x6FFFFFFF
using namespace std;

struct Node{
	double x, y;

	friend bool operator < (const Node &a, const Node &b){
		if(a.x == b.x)
			return a.y < b.y;
		return a.x < b.x;
	}
};

Node* Point = NULL;
/**
 * Calculate the distance between two points.
 * @return   [double, the distance between a and b]
 */
double _distance(const Node a, const Node b)
{
	return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
}

double smaller(double p, double q)
{
	return (p > q) ? q : p;
}
/**
 * [Find the closest distance, divide & conquer]
 * @param  left  [search from where]
 * @param  right [to where]
 * @return       [double, the smallest distance in the whole set of points]
 */
double Closest_distance(int left, int right)
{
	double d = INF;
	double distance_tmp;

	if(left == right)
		return 0;
	if(right == left+1)
		return _distance( Point[left], Point[right] );
	int mid = (left + right) / 2;

	d = smaller( Closest_distance(left,mid) , Closest_distance(mid,right) );

	for(int i=mid-1; i>=left && Point[mid].x - Point[i].x < d; i--){
		for(int j = mid+1; j<=right && Point[j].x - Point[mid].x < d && fabs( Point[i].y - Point[j].y) < d; j++){
			distance_tmp = _distance( Point[i], Point[j] );
			if(distance_tmp < d)
				d = distance_tmp;
		}
	}

	return d;
}

int main()
{
    int n;
    cin>>n;
    Point = new Node[n];
    for(int i=0; i<n ; i++){
    	cin>>Point[i].x>>Point[i].y;
    }
    sort(Point,Point+n);
    cout<<Closest_distance(0,n-1)<<endl;
    return 0;
}

固然,直接套用這個代碼提交到HDOJ會致使Exceed Time Limit,你懂的^_^
it

相關文章
相關標籤/搜索