HDU-1007-Quoit Design(分治,点+距离)

http://acm.hdu.edu.cn/showproblem.php?pid=1007

题意:

给出二维平面上的n个点,求其中最近的两个点距离的一般一半。

输入包含多组数据。每组数据第一行为n,表示点的个数;接下来n行,每行为一个点的坐标。当n为0时表示输入结束。每组数据输出一行,为最近的两个点的距离的一半。

思路:

首先暴力枚举肯定不行,数据范围1e5,

采用分治法,

  1,把n个点按x坐标进行排序,

  2,选取一个中点mid,将所有点分成两个部分(L,mid)和(mid+1,R)

    有三种情况:

    两个点都在左边

    两个点都在右边

    一个在左边,一个在右边 

  3,一二种结果很容易就可以求出得到Lmin和Rmin d=min(Lmin,Rmin);

  对于第三种情况,在以mid为中心,宽为2d的带状区域,选取此区域内的所有点,按照y轴进行排序,一一枚举这些点,更新最小距离即可。

  还可进一步剪枝,如果当前点到达基点的距离已经大于d,那么就可以更换下一个基点。

PS:对于左边的任意一点,右边的点一定落在一个d*2d的矩形中,且最多只需检查6个点(鸽巣原理),按照y轴排序后,进行线性扫描,此时合并的时间复杂度为O(n*logn),几乎为线性了。

HDU卡cin,记得用scanf。

代码:

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string>
#include<iomanip>
#include<algorithm>
#include<string.h>
#include<queue>
#include<cmath>

using namespace std;
const int maxn=1e5+10;
const int inf=1e10;
typedef long long ll;

struct node {double x,y;};

bool cmpx(node a,node b){return a.x<b.x;}
bool cmpy(node a,node b){return a.y<b.y;}

double Dis(node a,node b){return sqrt(pow(a.x-b.x,2)+pow(a.y-b.y,2));}

node a[maxn],b[maxn];

double cal(int s,int e)
{
    if(s==e) return inf;

    int mid=(s+e)/2;
    double d=min(cal(s,mid),cal(mid+1,e));
    
    int num=0;
    for(int i=mid; i>=s&&(a[mid].x-a[i].x)<d; i--) b[num++]=a[i];
    for(int i=mid+1; i<=e&&(a[i].x-a[mid].y)<d; i++) b[num++]=a[i];

    sort(b,b+num,cmpy);
    for(int i=0; i<num; i++)
    {
        for(int j=i+1; j<num&&b[j].y-b[i].y<d; j++)
        {
            if(Dis(b[i],b[j])<d)
             d=Dis(b[i],b[j]);
        }
    }
    return d;
}

int main()
{
    int n;
    while(cin>>n&&n)
    {
        for(int i=0; i<n; i++) scanf("%lf%lf",&a[i].x,&a[i].y);
        sort(a,a+n,cmpx);

        double ans=cal(0,n-1);
        printf("%.2lf
",ans/2.0);
    }
    system("pause");
    return 0;
}

    

原文地址:https://www.cnblogs.com/sweetlittlebaby/p/14327859.html