平面最近點對-分治
阿新 • • 發佈:2018-10-21
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 (inta, 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; }
平面最近點對-分治