分治算法求点集中最短距离

#include <iostream>
#include<stdio.h>
#include<cmath>

#define N 100
using namespace std;
struct Dian
    {
        int x;
        int y;
    };
chushihua(int x[],int n)
{
    for(int i=0;i<n;i++)
    {
        x[i]=i;
    }
    return 0;
}
input(struct Dian d[],int n)
{
    for(int i=0;i<n;i++)
    {
        cin>>d[i].x>>d[i].y;
    }
    return 0;
}
output(struct Dian d[],int n)
{
    for(int i=0;i<n;i++)
    {
        cout<<'('<<d[i].x<<','<<d[i].y<<')'<<' ';
        if(i%5==4)
        {
            cout<<endl;
        }
    }
    return 0;
}
output_(int X[],int n)
{
    for(int i=0;i<n;i++)
    {
        cout<<X[i]<<' ';
        if(i%5==4)
        {
            cout<<endl;
        }
    }
    return 0;
}
swap(int *p1,int *p2)
{
    int a=*p1;
    *p1=*p2;
    *p2=a;
    return 0;
}
swap(struct Dian *p1,struct Dian *p2)
{
    int a=p1->x,b=p1->y;
    p1->x=p2->x;p1->y=p2->y;
    p2->x=a;p2->y=b;
    return 0;
}
hebing(struct Dian d[],int m,int n,int z,int X[])//二分归并排序用合并函数
{
    int c[n-m+1];
    struct Dian b[n-m+1];
    int j=(m+n)/2+1,k=0,i=m;
    if(z==1)
    {
        while(i<=(n+m)/2||j<=n)
        {
            while((d[i].x>d[j].x||i>(m+n)/2)&&j<=n)
            {
                b[k].x=d[j].x;
                b[k].y=d[j].y;
                k++;
                j++;
            }
            while((d[i].x<=d[j].x||j>n)&&i<=(m+n)/2)
            {
                b[k].x=d[i].x;
                b[k].y=d[i].y;
                k++;
                i++;
            }
        }
        for(int i=m,k=0;i<=n;i++,k++)
        {
            d[i].x=b[k].x;
            d[i].y=b[k].y;
        }
    }
    else if(z==2)
    {
        while(i<=(n+m)/2||j<=n)
        {
            while((d[X[i]].y>d[X[j]].y||i>(m+n)/2)&&j<=n)
            {
                c[k]=X[j];
                k++;
                j++;
            }
            while((d[X[i]].y<=d[X[j]].y||j>n)&&i<=(m+n)/2)
            {
                c[k]=X[i];
                k++;
                i++;
            }
        }
        for(int i=m,k=0;i<=n;i++,k++)
        {
            X[i]=c[k];
        }
    }
    return 0;
}
paixu(struct Dian d[],int m,int n,int z,int X[])//二分归并排序
{
    if(z==1)
    {
        if(n-m>=2)
        {
            paixu(d,m,(m+n)/2,z,X);
            paixu(d,(m+n)/2+1,n,z,X);
            hebing(d,m,n,z,X);
        }
        else if(n-m==1)
        {
            if(d[m].x>d[n].x)
            {
                swap(d+m,d+n);
            }
            return 0;
        }
        else if(n==m)
        {
            return 0;
        }
    }
    if(z==2)
    {
        if(n-m>=2)
        {
            paixu(d,m,(m+n)/2,z,X);
            paixu(d,(m+n)/2+1,n,z,X);
            hebing(d,m,n,z,X);
        }
        else if(n-m==1)
        {
            if(d[X[m]].y>d[X[n]].y)
            {
                swap(X+m,X+n);
            }
            return 0;
        }
        else if(n==m)
        {
            return 0;
        }
    }
    return 0;
}
double min_mid(int m,int n,int X[],int YL[],int YR[],struct Dian d[],double dis)
//求点集最小距离时处理分界线两边dis窄缝间的最小距离
{
    int yL[(n+m)/2+1],yR[(n+m)/2+1];
    int lx=0,rx=0,ly=0,ry=0;//lx为左边窄缝第一个点序号,rx为右边最后一点序号
    for(int i=m;i<=n;i++)//把中间窄缝的点按x坐标分别放入两个数组
    {
        if(d[i].x>=d[(m+n)/2].x-dis&&d[i].x<=d[(m+n)/2].x)
        {
            lx=i;
            i=(m+n)/2+1;
        }
        if(d[i].x<=d[(m+n)/2].x+dis&&d[i].x>=d[(m+n)/2].x)
        {
            rx=i;
        }
    }
    if(rx==0)
    {
        return(dis);
    }
    for(int i=0;i<=(n-m)/2;i++)//把窄缝的点按y坐标顺序放入两个数组
    {
        if(YL[i]>=lx)
        {
            yL[ly]=YL[i];
            ly++;
        }
    }
    for(int i=0;i<=(n-m)/2-1;i++)//把窄缝的点按y坐标顺序放入两个数组
    {
        if(YR[i]<=rx)
        {
            yR[ry]=YR[i];
            ry++;
        }
    }
    int ry1=0,ry11[ry]={0};
    //ry1是用来标记右边是否有点在正负dis之间,ry11[ry]用来存放第一个在范围内的点的序号
    //因为是按y坐标来计算最小距离,左边下面的点在右边能找到的第一个在dis范围内的点才是他上面那个点需要开始考虑的起止点
    //这样可以防止每次检索右侧点从第0个开始
    for(int i=0;i<ly;i++)//比较窄缝左右两边点的距离
    {
        for(int j=ry11[0];j<ry;j++)
        {
            if(d[yR[j]].y<d[yL[i]].y+dis)
            {
                ry11[0]=ry;//初始化下一个点的比较的右侧起始位置,防止右边y值最大的点也不在范围内
                if(d[yR[j]].y>d[yL[i]].y-dis)
                {
                    dis=min(sqrt(pow(d[yL[i]].x-d[yR[j]].x,2)+pow(d[yL[i]].y-d[yR[j]].y,2)),dis);
                    ry11[ry1]=j;ry1++;
                    //只有ry1=0时是记录第一个在范围内的点,后续记录信息无用,只是让程序不要覆盖第一个点的信息。
                }
            }
        }
        ry1=0;
    }
    return(dis);
}
double mindistance(int m,int n,int X[],int Y[],struct Dian d[])
{
    if(n-m==1)
    {
        return(sqrt(pow(d[n].x-d[m].x,2)+pow(d[n].y-d[m].y,2)));
    }
    else if(n-m==2)
    {
        return(min(sqrt(pow(d[n].x-d[m].x,2)+pow(d[n].y-d[m].y,2)),min(sqrt(pow(d[n].x-d[m+1].x,2)+pow(d[n].y-d[m+1].y,2)),sqrt(pow(d[n-1].x-d[m].x,2)+pow(d[n-1].y-d[m].y,2)))));
    }
    else
    {
        int YL[(n-m+1)/2],YR[(n-m+1)/2];
        int yl=0,yr=0;
        double dis=0;
        for(int i=m;i<=n;i++)
        {
            if(Y[i]<=(n+m)/2)
            {
                YL[yl]=Y[i];
                yl++;
            }
            else
            {
                YR[yr]=Y[i];
                yr++;
            }
        }
        double a=mindistance(m,(m+n)/2,X,YL,d);
        double b=mindistance((m+n)/2+1,n,X,YR,d);
        dis=min(a,b);
        dis=min_mid(m,n,X,YL,YR,d,dis);
        return(dis);
    }
}
int main()
{
    freopen("input.txt","r",stdin);
    struct Dian Dianji[N];
    int X[N]={0},Y[N]={0};
    int n;
    cin>>n;
    input(Dianji,n);
    chushihua(X,n);
    chushihua(Y,n);
    output(Dianji,n);
    paixu(Dianji,0,n-1,1,X);//按x坐标排序结果
    output(Dianji,n);//按x坐标排序结果
    output_(X,n);//按x坐标排序结果
    paixu(Dianji,0,n-1,2,Y);//按Y坐标排序结果
    output_(Y,n);//按Y坐标排序结果
    cout<<mindistance(0,n-1,X,Y,Dianji)<<endl;
    return 0;
}

上一篇:065.Python框架Django-DRF


下一篇:C++ 动态联编和静态联编