zoukankan      html  css  js  c++  java
  • 洛谷 P1429 平面最近点对(加强版)(分治,归并排序)

    传送门


    解题思路

    按照x的大小分治。

    然后归并排序。

    归并时按照y值。

    然后步入难点

    假设我们已经求出了左半部分的最近距离和右半部分的最近距离,两个距离的较小值设为d。

    然后我们把划分左右两部分的中线的x值定为midx。

    很显然,最终的答案有三种情况:

    1. 两点在左半部分
    2. 两点在右半部分
    3. 一个点在左边,一个点在右边(即跨过中线)

    我们已经求出了1、2两种情况,还剩第三种情况。

    对于第三种情况,只有距离中线的距离<=x的点才有可能成为最终答案。

    所以我们在归并后,枚举一遍,找出所有abs(x-midx)<=d的点,放入数组q。

    然后枚举一遍q数组,想一想另一个点可能在什么地方?答案只有两部分:

    1. 这个点上方的点
    2. 这个点下放的点

    而且这两个点的y值的差一定小于d。

    而我们刚刚的归并排序就是按照y值排序的,所以当某个点y值的差大于d时,可以直接结束循环。

    对于时间复杂度,可以证明符合条件的点很少(最多6个)。

    证明略。

    注:求midx时一定要在分治前面求,否则分治结束后会改变点在数组中的位置(因为是按照y值归并的)。

    AC代码

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<cmath>
     4 #include<cstdio>
     5 #include<iomanip>
     6 using namespace std;
     7 const int maxn=200005;
     8 int n;
     9 struct Point{
    10     double x,y;
    11 }p[maxn],q[maxn];
    12 bool cmp(const Point &a,const Point &b){
    13     return a.x<b.x; 
    14 } 
    15 double dis(const Point &a,const Point &b){
    16     return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
    17 }
    18 double divide(int l,int r){
    19     if(l==r) return 1ll<<60;
    20     int mid=(l+r)/2;
    21     double midx=p[mid].x;
    22     double d=min(divide(l,mid),divide(mid+1,r));
    23     int p1=l,p2=mid+1,tot=0;
    24     while(p1<=mid||p2<=r){
    25         if(p1<=mid&&(p2>r||p[p1].y<p[p2].y)){
    26             q[++tot]=p[p1++];
    27         }else{
    28             q[++tot]=p[p2++];
    29         }
    30     }
    31     for(int i=1;i<=tot;i++){
    32         p[l+i-1]=q[i];
    33     }
    34     tot=0;
    35     for(int i=l;i<=r;i++){
    36         if(abs(p[i].x-midx)<=d) q[++tot]=p[i];
    37     }
    38     for(int i=1;i<=tot;i++){
    39         for(int j=i-1;j>=1&&q[i].y-q[j].y<=d;j--){
    40             d=min(d,dis(q[i],q[j]));
    41         }
    42         for(int j=i+1;j<=tot&&q[j].y-q[i].y<=d;j++){
    43             d=min(d,dis(q[i],q[j]));
    44         }
    45     }
    46     return d;
    47 }
    48 int main()
    49 {
    50     cin>>n;
    51     for(int i=1;i<=n;i++){
    52         scanf("%lf%lf",&p[i].x,&p[i].y);
    53     }
    54     sort(p+1,p+n+1,cmp);
    55     cout<<fixed<<setprecision(4)<<divide(1,n)<<endl;
    56     return 0;
    57 }
  • 相关阅读:
    抽象类和接口【转】
    JQuery中的事件总结
    ExecuteNonQuery()返回受影响行数不适用select语句
    用js获取对象之前首先检测元素是否存在
    页面如何自动出现滚动条(overflow属性用法)
    今天调试程序遇到了一个致命问题语法错误操作符丢失
    JQuery选择器学习总结JQuery选择器
    css !important用法CSS样式使用优先级判断
    JQuery操作DOM总结
    JQuery特效与动画总结
  • 原文地址:https://www.cnblogs.com/yinyuqin/p/12308565.html
Copyright © 2011-2022 走看看