JZOJ3193. 【中山市选2013】点

题目大意

给出两个点集,判断能否对其中一个点集进行旋转、平移、翻转、放大后与另一个重合。

扯淡

第一眼看上去似乎很难
看题解看到懵逼,别人的方法感觉不太可靠
于是随手写下自己的方法发现跑得挺快
咳咳

正题

先不看题目。
假设有两张纸片,要判断这两张纸片是否相似,怎么做?
这里写图片描述

判断相似,肯定要先把它们放在一起。
这里写图片描述

至于怎么放在一起,如果实际操作,只需大致找一个点。
但是在程序中无法随便找一个点,所以直接找它们的重心
重心有一个性质,只要两个图形相似,那么它们重心的相对位置相同。

重心的求法:
重心(x,y)
x=(Σx[i])/n
y=(Σy[i])/n
其实就是x与y的平均值。
然后把两个点集分别以重心为原点,建立新的坐标系。


接下来,如何判断两个图形相似?
在现实中,其实可以旋转其中一个,然后看两个图形的边缘是否相同。
但是如果我们这样做的话,时间将是平方级。

想想可以直到,如果两个图形相似,那么它们的点与原点的连边一定成相同的比例。
那么一个点集中的最远点,在另一个点集中一定相对应
所以可以求出一个点集与另一个的比例,然后从两个最远点开始,判断两个点集是否相同。
如果两个点集都有多个最远点,那么从其中一个的一个最远点开始,和另一个点集的所有最远点相匹配。

因为所有点都是整点,所以25000以内的最远点个数不超20个。

code

350+行。。。
其实翻转前后基本一样,两个快拍可以自带,某些细节可以优化
最简应该100行左右吧。。

#include <iostream>
#include <cstdio>
#include <cmath>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define error 0.000001
using namespace std;

long double x[25001];
long double y[25001];
long double ang[25001];
long double len[25001];
long double X[25001];
long double Y[25001];
long double Ang[25001];
long double Len[25001];
int n,i,j,k,l,m,Q,ls;
long double avex,avey,maxlen,maxlen_ang,Avex,Avey,Maxlen,Maxlen_ang,s,ang1,ang2;
bool bz;

void qsort(int l,int r)
{
    int i,j,k;
    long double mid,Mid;

    i=l;
    j=r;
    mid=ang[(l+r)/2];
    Mid=len[(l+r)/2];

    while (i<=j)
    {
        while ((ang[i]<mid) || ((ang[i]==mid) && (len[i]<Mid))) i++;
        while ((ang[j]>mid) || ((ang[j]==mid) && (len[j]>Mid))) j--;

        if (i<=j)
        {
            ang[0]=ang[i];
            ang[i]=ang[j];
            ang[j]=ang[0];
            len[0]=len[i];
            len[i]=len[j];
            len[j]=len[0];

            i++;
            j--;
        }
    }

    if (l<j)
    qsort(l,j);
    if (i<r)
    qsort(i,r);

    return;
}

void Qsort(int l,int r)
{
    int i,j,k;
    long double mid,Mid;

    i=l;
    j=r;
    mid=Ang[(l+r)/2];
    Mid=Len[(l+r)/2];

    while (i<=j)
    {
        while ((Ang[i]<mid) || ((Ang[i]==mid) && (Len[i]<Mid))) i++;
        while ((Ang[j]>mid) || ((Ang[j]==mid) && (Len[j]>Mid))) j--;

        if (i<=j)
        {
            Ang[0]=Ang[i];
            Ang[i]=Ang[j];
            Ang[j]=Ang[0];
            Len[0]=Len[i];
            Len[i]=Len[j];
            Len[j]=Len[0];

            i++;
            j--;
        }
    }

    if (l<j)
    Qsort(l,j);
    if (i<r)
    Qsort(i,r);

    return;
}

int main()
{
    scanf("%d",&n);
    fo(i,1,n)
    scanf("%Lf%Lf",&x[i],&y[i]),avex+=x[i],avey+=y[i];
    avex/=n,avey/=n;
    fo(i,1,n)
    {
        x[i]-=avex;
        y[i]-=avey;
        len[i]=sqrt(x[i]*x[i]+y[i]*y[i]);

        if ((x[i]==0) && (y[i]>0))
        ang[i]=90;
        else
        if ((x[i]==0) && (y[i]<0))
        ang[i]=270;
        else
        if ((x[i]>0) && (y[i]==0))
        ang[i]=0;
        else
        if ((x[i]<0) && (y[i]==0))
        ang[i]=180;
        else
        if ((x[i]==0) && (y[i]==0))
        ang[i]=-1;
        else
        {
            ang[i]=180*atan(y[i]/x[i])/M_PI;
            if ((x[i]<0) && (y[i]>0))
            ang[i]+=180;
            else
            if ((x[i]<0) && (y[i]<0))
            ang[i]+=180;
            else
            if ((x[i]>0) && (y[i]<0))
            ang[i]+=360;
        }
    }

    j=0;
    maxlen=0;
    fo(i,1,n)
    if (len[i]>maxlen)
    {
        maxlen=len[i];
        j=i;
    }
    maxlen_ang=ang[j];
    fo(i,1,n)
    if (ang[i]>=0)
    {
        ang[i]=ang[i]-maxlen_ang;
        if (ang[i]<0)
        ang[i]+=360;
    }
    qsort(1,n);
    if (ang[1]<0)
    ang[1]=0;

    scanf("%d",&Q);
    for (;Q;Q--)
    {

    Avex=0;
    Avey=0;
    scanf("%d",&j);
    fo(i,1,j)
    scanf("%Lf%Lf",&X[i],&Y[i]),Avex+=X[i],Avey+=Y[i];

    if (j!=n)
    {
        printf("No\n");
        continue;
    }

    Avex/=n,Avey/=n;
    fo(i,1,n)
    {
        X[i]-=Avex;
        Y[i]-=Avey;
        Len[i]=sqrt(X[i]*X[i]+Y[i]*Y[i]);

        if ((X[i]==0) && (Y[i]>0))
        Ang[i]=90;
        else
        if ((X[i]==0) && (Y[i]<0))
        Ang[i]=270;
        else
        if ((X[i]>0) && (Y[i]==0))
        Ang[i]=0;
        else
        if ((X[i]<0) && (Y[i]==0))
        Ang[i]=180;
        else
        if ((X[i]==0) && (Y[i]==0))
        Ang[i]=-1;
        else
        {
            Ang[i]=180*atan(Y[i]/X[i])/M_PI;
            if ((X[i]<0) && (Y[i]>0))
            Ang[i]+=180;
            else
            if ((X[i]<0) && (Y[i]<0))
            Ang[i]+=180;
            else
            if ((X[i]>0) && (Y[i]<0))
            Ang[i]+=360;
        }
    }

    j=0;
    Maxlen=0;
    fo(i,1,n)
    if (Len[i]>Maxlen)
    {
        Maxlen=Len[i];
        j=i;
    }
    Maxlen_ang=Ang[j];
    fo(i,1,n)
    if (Ang[i]>=0)
    {
        Ang[i]=Ang[i]-Maxlen_ang;
        if (Ang[i]<0)
        Ang[i]+=360;
    }
    Qsort(1,n);
    if (Ang[1]<0)
    Ang[1]=0;

    if (maxlen)
    {
        s=Maxlen/maxlen;
        fo(i,1,n)
        Len[i]/=s;
    }

    fo(i,1,n)
    if (len[1]==Len[i])
    {
        bz=1;
        k=i;
        ang2=0;
        fo(j,2,n)
        {
            ls=k;
            k=k%n+1;
            ang2+=(Ang[k]>=Ang[ls])?(Ang[k]-Ang[ls]):((360-Ang[ls])+Ang[k]);

            if (((abs(len[j]-Len[k]))>error) || ((abs(ang[j]-ang2))>error))
            {
                bz=0;
                break;
            }
        }

        if (bz)
        break;
    }

    if (bz)
    {
        printf("Yes\n");
        continue;
    }





    fo(i,1,n)
    {
        X[i]=-X[i];
        Y[i]=Y[i];
        Len[i]=sqrt(X[i]*X[i]+Y[i]*Y[i]);

        if ((X[i]==0) && (Y[i]>0))
        Ang[i]=90;
        else
        if ((X[i]==0) && (Y[i]<0))
        Ang[i]=270;
        else
        if ((X[i]>0) && (Y[i]==0))
        Ang[i]=0;
        else
        if ((X[i]<0) && (Y[i]==0))
        Ang[i]=180;
        else
        if ((X[i]==0) && (Y[i]==0))
        Ang[i]=-1;
        else
        {
            Ang[i]=180*atan(Y[i]/X[i])/M_PI;
            if ((X[i]<0) && (Y[i]>0))
            Ang[i]+=180;
            else
            if ((X[i]<0) && (Y[i]<0))
            Ang[i]+=180;
            else
            if ((X[i]>0) && (Y[i]<0))
            Ang[i]+=360;
        }
    }

    j=0;
    Maxlen=0;
    fo(i,1,n)
    if (Len[i]>Maxlen)
    {
        Maxlen=Len[i];
        j=i;
    }
    Maxlen_ang=Ang[j];
    fo(i,1,n)
    if (Ang[i]>=0)
    {
        Ang[i]=Ang[i]-Maxlen_ang;
        if (Ang[i]<0)
        Ang[i]+=360;
    }   
    Qsort(1,n);
    if (Ang[1]<0)
    Ang[1]=0;

    if (maxlen)
    {
        s=Maxlen/maxlen;
        fo(i,1,n)
        Len[i]/=s;
    }

    fo(i,1,n)
    if (len[1]==Len[i])
    {
        bz=1;
        k=i;
        ang2=0;
        fo(j,2,n)
        {
            ls=k;
            k=k%n+1;
            ang2+=(Ang[k]>=Ang[ls])?(Ang[k]-Ang[ls]):((360-Ang[ls])+Ang[k]);

            if (((abs(len[j]-Len[k]))>error) || ((abs(ang[j]-ang2))>error))
            {
                bz=0;
                break;
            }
        }

        if (bz)
        break;
    }

    if (bz)
    printf("Yes\n");
    else
    printf("No\n");

    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值