哈,就这样水过去了??
不科学呀。
好吧,平面最近点对(伪)。
就是一个二分的事:
1.以x排序。
2.二分,递归求解。
具体来讲,主要难在如何求 横跨两个区域的最近点对 这一环节。
那么是这样做的:首先我们会有个ans是左右的最小值对吧。
我们只考虑在划分线左右两边不超过ans的那些点(即为[_l, _r])
然后把这些点暴力求解即可AC按照y排序,这样的情况下,再只考虑与一个点上下不超过ans的那些点即可......
那么下面是我的暴力版写法:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /// poj 3714 2 #include <cstdio> 3 #include <iostream> 4 #include <algorithm> 5 #include <cmath> 6 using namespace std; 7 typedef long long LL; 8 const int N = 100010; 9 const double INF = (double)(0x7f7f7f7f); 10 11 struct Point { 12 LL x, y; 13 bool f; 14 bool operator < (const Point &k) const { 15 return x < k.x; 16 } 17 }p[N << 1]; 18 19 inline double dis(int i, int j) { 20 return sqrt((double)((p[i].x - p[j].x) * (p[i].x - p[j].x) + (p[i].y - p[j].y) * (p[i].y - p[j].y))); 21 } 22 23 double twsolve(int l, int r) { 24 if(l == r) return INF; 25 int mid = (l + r) >> 1; 26 double k = min(twsolve(l, mid), twsolve(mid + 1, r)); 27 int _l, _r; 28 for(_l = mid; _l >= l; _l--) { 29 if(p[_l].x <= p[mid + 1].x - k) { 30 break; 31 } 32 } 33 for(_r = mid + 1; _r <= r; _r++){ 34 if(p[_r].x >= p[mid].x + k) { 35 break; 36 } 37 } 38 if(_l < l) _l = l; 39 if(_r > r) _r = r; 40 double ans = k; 41 for(int i = _l; i <= mid; i++) { 42 for(int j = mid + 1; j <= _r; j++) { 43 if(!(p[i].f ^ p[j].f)) continue; 44 ans = min(ans, dis(i, j)); 45 } 46 } 47 return ans; 48 } 49 50 int main() { 51 int T, n; 52 scanf("%d", &T); 53 while(T--) { 54 scanf("%d", &n); 55 for(int i = 1; i <= n; i++) { 56 scanf("%I64d %I64d", &p[i].x, &p[i].y); 57 p[i].f = 0; 58 59 } 60 for(int i = 1; i <= n; i++) { 61 scanf("%I64d %I64d", &p[i + n].x, &p[i + n].y); 62 p[i + n].f = 1; 63 } 64 sort(p + 1, p + (n << 1) + 1); 65 printf("%.3lf ", twsolve(1, n << 1)); 66 //cout << twsolve(1, n << 1) << endl; 67 } 68 return 0; 69 }
附赠数据生成器:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<cstdlib> 3 #include<ctime> 4 using namespace std; 5 int main() 6 { 7 freopen("in.in","w",stdout); 8 srand(time(0)); 9 printf("1 "); 10 int n = rand() % 100000 + 1; 11 printf("%d ", n); 12 n = n << 1; 13 for(int i = 1; i <= n; i++) { 14 printf("%d %d ", rand() % 1000010 + 1, rand() % 1000010 + 1); 15 } 16 return 0; 17 }
[update]2018.10.20
这回写的是正规的nlogn,洛谷P1429 平面最近点对
y的排序使用归并,少一个排序的log。
然后发现一点小问题:我写的错误的程序A了,但是正确的却WA了......以后写了对的正解再发上来吧。