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

平面最近點對-分治

space name amp point syn cin std 很多 lin

n2的暴力就算了。。

我們直接考慮怎樣優化:

我們考慮到可以先按x排序,然後分治,先分別求解兩個子問題。

假設我們已經求得了兩個子問題的答案。

那麽如果合並時,答案能夠更新,當且僅當兩個子區間中存在更近的點對。

那麽分別枚舉兩個子區間的點?? 還不是和n2一樣T掉。。

實際上,有很多點是沒必要枚舉的。

因為我們已經得到了兩個子區間的答案,

那麽如果存在更小的答案,可能的區間也僅僅只在[x[Mid]-min (ans1, ans2), x[mid]+min (ans1, ans2)];

所以呢,這要在這個區間中暴力枚舉更新就好了。。

這樣的話,限制稍微寬松一些,但肯定可以保證不會漏掉答案。。一般沒人無聊到去卡掉這個

#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;

int n;
double Mx;

struct Point {
    double x,y;
    bool operator < (Point &a) {
        return x<a.x || (x==a.x && y<a.y);
    }
}d[200010];

inline double Calc (int
a, int b) { return sqrt (fabs (d[a].x-d[b].x)*fabs (d[a].x-d[b].x)+fabs (d[a].y-d[b].y)*fabs (d[a].y-d[b].y)); } int search (int l, int r, double val) { int Mid; while (l<r) { Mid= (l+r) >> 1; if (d[Mid].x>=val) r=Mid; else l=Mid+1; } return r; }
double Solve (int l, int r) { if (l==r) return 2147483647; double Ans; int Mid= (l+r) >> 1,Lp,Rp; Ans=min (Solve (l, Mid), Solve (Mid+1, r)); Lp=search (l, Mid, d[Mid].x-Ans), Rp=search (Mid+1, r, d[Mid+1].x+Ans); for (int i=Lp;i<=Mid;++i) for (int j=Mid+1;j<=Rp;++j) Ans=min (Ans, Calc (i, j)); return Ans; } int main () { std::ios::sync_with_stdio (false); cin >> n; for (int i=1;i<=n;++i) cin >> d[i].x >> d[i].y; sort (d+1, d+n+1); printf ("%.4lf\n", Solve (1, n)); return 0; }

平面最近點對-分治