洛谷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; }