1. 程式人生 > >【題解】平面最近點對(加強版)

【題解】平面最近點對(加強版)

double clas .org ace gpo bits scanf 簡單 name

洛谷P1429 很久以前就見過並想做的一道題……

但大概是那個時候太蒻竟然一直不敢做呢,想想時間真的過得好快,從寫‘Hello World’到如今,其實也不過是短短的一個學期呀。

這道題主要用分治的思想來做,對所有的點排一下序,然後每一次分成兩隊來處理。若一隊的節點數<=3那麽就直接暴力求解。可以註意到因為點都是排好序的,所以兩邊當中的點的距離>= abs(P[i].x - P[mid].x)。那麽如果這個距離已經大於我們當前找到的最優答案,顯然就不需要再去計算一遍啦。那麽我們再把那些還可能含有最優答案的點拿出來暴力處理,因為有前面一個條件的限制,所以實際上這些點的數量是十分有限的。

雖然是道簡單的題目,但從不敢做到今天能夠自己寫出代碼來,還是很受鼓勵的吧。

#include <bits/stdc++.h>
using namespace std;
#define INF 999999999.00
#define maxn 2005000
int n;
struct node
{
    double x, y;
}P[maxn];
node q1[maxn], q2[maxn];

bool cmp(node a, node b)
{
    return a.x < b.x;
}

double Dis(double x1, double y1, double x2, double
y2) { return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); } double Get_ans(int cnt, int cnt2) { double ans = INF; for(int i = 1; i <= cnt; i ++) for(int j = 1; j <= cnt2; j ++) ans = min(ans, Dis(q1[i].x, q1[i].y, q2[j].x, q2[j].y)); return ans; }
double Violence(int l, int r) { double ans = INF; for(int i = l; i <= r; i ++) for(int j = i + 1; j <= r; j ++) ans = min(ans, Dis(P[i].x, P[i].y, P[j].x, P[j].y)); return ans; } double Div(int l, int r) { int cnt = 0, cnt2 = 0; double ans, ans1, ans2; int mid = (l + r) >> 1; if(r - l > 3) ans1 = Div(l, mid), ans2 = Div(mid + 1, r); else return Violence(l, r); ans = min(ans1, ans2); for(int i = mid + 1; i <= r; i ++) if(P[i].x - P[mid].x < ans) q1[++ cnt] = P[i]; else break; for(int i = mid; i >= l; i --) if(P[mid].x - P[i].x < ans) q2[++ cnt2] = P[i]; else break; return min(ans, Get_ans(cnt, cnt2)); } int main() { scanf("%d", &n); for(int i = 1; i <= n; i ++) scanf("%lf%lf", &P[i].x, &P[i].y); sort(P + 1, P + 1 + n, cmp); printf("%.4lf", Div(1, n)); return 0; }

【題解】平面最近點對(加強版)