多校联合第七场1003Swordsman(判断简单多边形是否是轴对称图形)

简单多边形是边不相交的多边形,又称佐敦多边形,因为佐敦曲线定理可以用来证明这样的多边形能将平面分成两个区域,即区内和区外。

这题看到的时候顿时蛋疼了,我在FJNU的比赛和长沙的华南赛都遇到过类似的题目,FJNU的比赛各边是和x,y轴都是平行的,只需枚举4个方向的对称轴,长沙和这题很相似,要枚举所有对称轴,数据比较小,这题数据比较大,20000 ,枚举对称轴是o(n),判断是否是对称轴又是o(n),复杂度是O(n^2)写的麻烦点很容易暴的,看了题解的NlogN方法,利用字符串处理,在网上找了类似POI2007的题解。

这个代码很快, 而且可以计算出对称轴的个数 代码出处 http://hi.baidu.com/nplusnplusnplu/blog/item/d260baef2e9e9c5879f055cb.html

#include<iostream>
#include<algorithm>
#include<cstring>
#include<iomanip>
#include<cmath>
#include<cstdio>
using namespace std;

const int maxn=20010;
int N,M,Tot,next[maxn];
int x[maxn],y[maxn];
long long ans;

struct Point
{
    long long ed,ag;
}P[2*maxn],Q[maxn];

bool operator==(Point A,Point B)
{
    return A.ed==B.ed&&A.ag==B.ag;
}

void scanInt(int &x)
{
    char ch;
    while(ch=getchar(),ch<'0'||ch>'9');
    x=ch-'0';
    while(ch=getchar(),ch>='0'&&ch<='9')x*=10,x+=ch-'0';
}

void FindNext()
{
    next[0]=-1;
    next[1]=0;
    for(int i=2;i<N;++i)
    {
        int p=next[i-1];
        for(;!(Q[p]==Q[i-1])&&p;)
        p=next[p];
        if(Q[p]==Q[i-1])next[i]=p+1;else next[i]=0;
    }
} 

bool CP(long long a,long long b,long long c,long long d)
{
    return a*d-b*c>0;
}

int main()
{
    int Case;
    while (~scanf("%d",&N))
    {
        for(int i=0;i<N;++i)
        {
            scanf("%I64d",x+i);
            scanf("%I64d",y+i);
        }
        x[N]=x[0];
        y[N]=y[0];
        x[N+1]=x[1];
        y[N+1]=y[1];
        for(int i=0;i<N;++i)
        {
            long long tmp=x[i+1]-x[i];
            tmp*=tmp;
            P[i].ed=tmp;
            tmp=y[i+1]-y[i];
            tmp*=tmp;
            P[i].ed+=tmp;
            tmp=x[i+2]-x[i];
            tmp*=tmp;
            P[i].ag=tmp;
            tmp=y[i+2]-y[i];
            tmp*=tmp;
            P[i].ag+=tmp;//构造正序边,ed,ag分别存点i到i+1和点i到i+2的距离的平方
            if(CP(x[i+2]-x[i],y[i+2]-y[i],x[i+1]-x[i],y[i+1]-y[i]))P[i].ag=-P[i].ag;
        }
        for(int i=2;i<=N;++i)
        {
            long long tmp=x[i]-x[i-1];
            tmp*=tmp;
            Q[N-i].ed=tmp;
            tmp=y[i]-y[i-1];
            tmp*=tmp;
            Q[N-i].ed+=tmp;
            tmp=x[i]-x[i-2];
            tmp*=tmp;
            Q[N-i].ag=tmp;
            tmp=y[i]-y[i-2];
            tmp*=tmp;
            Q[N-i].ag+=tmp;
            if(!CP(x[i-2]-x[i],y[i-2]-y[i],x[i-1]-x[i],y[i-1]-y[i]))Q[N-i].ag=-Q[N-i].ag;
        }
        long long tmp=x[1]-x[0];
        tmp*=tmp;
        Q[N-1].ed=tmp;
        tmp=y[1]-y[0];
        tmp*=tmp;
        Q[N-1].ed+=tmp;
        tmp=x[1]-x[N-1];
        tmp*=tmp;
        Q[N-1].ag=tmp;
        tmp=y[1]-y[N-1];
        tmp*=tmp;
        Q[N-1].ag+=tmp;
        if(!CP(x[N-1]-x[1],y[N-1]-y[1],x[0]-x[1],y[0]-y[1]))Q[N-1].ag=-Q[N-1].ag;
        memcpy(P+N,P,N*sizeof(Point));

        int p=0;
        ans=0;
        FindNext();
        for(int i=0;i<(N<<1)-1;++i)
        {
            for(;!(P[i]==Q[p])&&p;)p=next[p];
            if(P[i]==Q[p])
            {
                if(p==N-1)
                {
                    ans++;//ans记录对称轴的个数 
                    p=next[p];
                    if(P[i]==Q[p])p++;
                    continue;
                }
                p++;
            }
        }
        if(ans)printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

自己整理的代码:有点慢

 

#include <stdio.h>
#include <string.h>

const int maxn=20010;
int N, M, next[maxn], x[maxn], y[maxn];
int ;
long long ans;

struct Point{
    long long ed,ag;
}P[2*maxn],Q[maxn];
bool operator == (Point A,Point B)
{
     return A.ed==B.ed && A.ag==B.ag;
}
void Findnext ()
{
    next[0]=-1;
    next[1]=0;
    for (int i=2 ; i<N ; ++i)
    {
        int p=next[i-1];
        for (; !(Q[p]==Q[i-1])&&p ; p=next[p]);
        if(Q[p]==Q[i-1])next[i]=p+1;
        else next[i]=0;
    }
}
inline bool comp(long long a,long long b,long long c,long long d)
{
     return a*d-b*c>0;
}
inline long long sqr(long long x)
{
    return x*x;
}

void Getinf()
{
    for (int i=0 ; i<N ; ++i)//正序
    {
        P[i].ed=sqr(x[i+1]-x[i])+sqr(y[i+1]-y[i]);
        P[i].ag=sqr(x[i+2]-x[i])+sqr(y[i+2]-y[i]);
        //printf("%d  %d\n", P[i].ed, P[i].ag);
        if(comp(x[i+2]-x[i],y[i+2]-y[i],x[i+1]-x[i],y[i+1]-y[i]))P[i].ag=-P[i].ag;
    }
    for (int i=2 ; i<=N ; ++i )//反序
    {
        Q[N-i].ed=sqr(x[i]-x[i-1])+sqr(y[i]-y[i-1]);
        Q[N-i].ag=sqr(x[i]-x[i-2])+sqr(y[i]-y[i-2]);
        if(!comp(x[i-2]-x[i],y[i-2]-y[i],x[i-1]-x[i],y[i-1]-y[i]))Q[N-i].ag=-Q[N-i].ag;
    }
    Q[N-1].ed=sqr(x[1]-x[0])+sqr(y[1]-y[0]);
    Q[N-1].ag=sqr(x[1]-x[N-1])+sqr(y[1]-y[N-1]);
    //printf("%d  %d\n", Q[N-1].ed, Q[N-1].ag);
    if(!comp(x[N-1]-x[1],y[N-1]-y[1],x[0]-x[1],y[0]-y[1]))Q[N-1].ag=-Q[N-1].ag;
    memcpy(P+N , P , N*sizeof(Point));
}

int main ()
{
    while (~scanf("%d",&N))
    {
        for (int i=0 ; i<N ; ++i)
        {
            scanf("%I64d%I64d",x+i,y+i);
        }
        x[N]=x[0];
        y[N]=y[0];
        x[N+1]=x[1];
        y[N+1]=y[1];
        Getinf();
        int p=0 ;
        ans=0;
        Findnext();
        for (int i=0 ; i<(N<<1)-1; ++i)
        {
            for (;!(P[i]==Q[p])&&p ; p=next[p]);
            if(P[i]==Q[p])
            {
                if(p==N-1)
                {
                    ans++;
                    p=next[p];
                    if(P[i]==Q[p])p++;
                    continue;
                }
                p++;
            }
        }
        if(ans)printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}


 

你可能感兴趣的:(多校联合第七场1003Swordsman(判断简单多边形是否是轴对称图形))