欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

poj3714 Raid(分治)

程序员文章站 2022-03-02 23:03:44
...

题意

给两个点集,求两个点集中任意两点的最小距离。

 

题解

分治+标记

如果会了最近点对问题,就可以做了。
只要在匹配时注意一下不同集合才能匹配就可以了。
我用key做标记:key=1、3表示在集合A,key=2、4在集合B;其中key=1、2表示在a[mid]的左边,key=3、4表示在右边。所以1要和4匹配,2和3匹配。

 

代码

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const double inf=1<<30;
const int maxn=200010;

double dis(double x1,double y1,double x2,double y2)
{
    return sqrt( (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2) );
}

int n;
struct node
{
    double x,y;
    int key;
}a[maxn],b[maxn];int bn;
bool cmpx(node a1,node a2)
{
    return a1.x<a2.x;
}
bool cmpy(node b1,node b2)
{
    return b1.y<b2.y;
}

double solve(int l,int r)//求第l~r个点中的最近点对 
{
    if(l==r) return inf;
    int mid=l+r>>1;
    double d=min(solve(l,mid),solve(mid+1,r));
    
    bn=0;
    for(int i=mid;i>=l && a[mid].x-a[i].x<=d;i--) b[++bn]=a[i];//key->1,2
    for(int i=mid+1;i<=r && a[i].x-a[mid].x<=d;i++) b[++bn]=a[i],b[bn].key+=2;//key->3,4
    
    sort(b+1,b+bn+1,cmpy);
    for(int i=1;i<bn;i++)
    {
        for(int j=i+1;j<=bn;j++)
        {
            if( b[i].key==1&&b[j].key==4 || b[i].key==4&&b[j].key==1 ||
                b[i].key==2&&b[j].key==3 || b[i].key==3&&b[j].key==2 )
            {
                if(b[j].y-b[i].y>=d) break;
                d=min(d,dis(b[i].x,b[i].y,b[j].x,b[j].y));
            }
        }
    }
    
    return d;
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%lf%lf",&a[i].x,&a[i].y),a[i].key=1;
        n*=2;
        for(int i=n/2+1;i<=n;i++) scanf("%lf%lf",&a[i].x,&a[i].y),a[i].key=2;
        sort(a+1,a+n+1,cmpx);
        double ans=solve(1,n);
        printf("%.3lf\n",ans);
    }
    return 0;
}