1. 程式人生 > >分治_平面最近點對_POJ3714_Raid

分治_平面最近點對_POJ3714_Raid

思路分析:

    AC程式碼如下, 就下面程式碼而言, 比較容易理解, 不予分析, 但是應該強調, 下面的程式碼不能算作典型的分治法求解平面最近點對的演算法, 為什麼這麼說 ? 因為經典的分治法求解平面最近點對的演算法(可參考演算法導論第33章第4節)的最壞情況時間複雜度為O(nlg(n)), 然而就下面給出的程式碼而言其最壞情況時間複雜度的階嚴格高於nlg(n)

//POJ3714_Raid
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long double LD;
const int MAX = 2e5 + 5; const LD NIL = 1e15; 
pair<pair<int, int>, bool> p[MAX], ptmp[MAX];//first:座標, second:true表示電站,false表示代理人 
bool cmpx(const pair<pair<int, int>, bool> a, pair<pair<int, int>, bool> b){
	return a.first.first < b.first.first;
}
//返回p[l...r]中電站和代理人的最小距離,  
LD solve(int l, int r){
	if(l == r) return NIL;
	int mid = (l + r) >> 1, midx = p[mid].first.first;
	LD ansl = solve(l, mid), ansr = solve(mid + 1, r), ans; ans = min(ansl, ansr);
	int ptmplen = 0;
	for(int i = l; i <= r; ++i) if(abs(p[i].first.first - midx) <= ans) ptmp[++ptmplen] = p[i];
	for(int i = 1; i <= ptmplen; ++i)
		for(int j = i + 1; j <= ptmplen ; ++j)
			if(ptmp[i].second != ptmp[j].second) 
				ans = min(ans, sqrt((LD)(ptmp[i].first.first - ptmp[j].first.first) 
						              * (ptmp[i].first.first - ptmp[j].first.first) 
								+ (LD)(ptmp[i].first.second - ptmp[j].first.second) 
								* (ptmp[i].first.second - ptmp[j].first.second)));	
	return ans;
}
int main(){
	int T; scanf("%d", &T); 
	while(T--){
		int N; scanf("%d", &N);
		for(int i = 1, x, y; i <= N; ++i) 
			scanf("%d %d", &x, &y), p[i] = make_pair(make_pair(x, y), true);
		for(int i = N + 1, x, y; i <= N << 1; ++i)
			scanf("%d %d", &x, &y), p[i] = make_pair(make_pair(x, y), false);
		sort(p + 1, p + 2 * N + 1, cmpx);//先按照橫座標非遞減排序 
		printf("%.3Lf\n", solve(1, N << 1));
	}
}