poj3714 Raid(分治)

题意

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

题解

分治+标记

如果会了最近点对问题,就可以做了。
只要在匹配时注意一下不同集合才能匹配就可以了。
我用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;
}

猜你喜欢

转载自blog.csdn.net/A_Bright_CH/article/details/81365814
今日推荐