多校联合第七场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;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我来为你解答这个问题。 首先,我们需要了解一下十二位十进制计数器的原理。这个计数器可以使用多种电子元件来实现,比如集成电路、数字电路等。在这里,我们可以使用Verilog HDL来描述这个计数器。 以下是一个简单的Verilog HDL代码,用于实现一个十二位十进制计数器: ``` module counter12( input clk, //时钟信号 input rst, //复位信号 output reg [11:0] count //计数器输出 ); always @(posedge clk or posedge rst) if(rst) count <= 12'h000; //复位计数器 else count <= count + 1; //计数器加1 endmodule ``` 这个代码中,我们使用always块来描述计数器的行为。当时钟信号(clk)上升沿到来时,计数器的值会加1。同时,当复位信号(rst)上升沿到来时,计数器的值会被重置为0。 接下来,我们需要将计数器的值显示在数码管上。同样,我们可以使用Verilog HDL来描述数码管的行为。 以下是一个简单的Verilog HDL代码,用于实现一个数码管控制器: ``` module seg_controller( input [11:0] count, //计数器输出 output reg [6:0] seg, //数码管段选输出 output reg [3:0] dig //数码管位选输出 ); always @(count) case(count % 12) //取模计算当前位数 0: begin seg = 7'b1000000; dig = 4'b1110; end //显示0 1: begin seg = 7'b1111001; dig = 4'b1101; end //显示1 2: begin seg = 7'b0100100; dig = 4'b1011; end //显示2 3: begin seg = 7'b0110000; dig = 4'b0111; end //显示3 4: begin seg = 7'b0011001; dig = 4'b1110; end //显示4 5: begin seg = 7'b0010010; dig = 4'b1011; end //显示5 6: begin seg = 7'b0000010; dig = 4'b1011; end //显示6 7: begin seg = 7'b1111000; dig = 4'b1110; end //显示7 8: begin seg = 7'b0000000; dig = 4'b1011; end //显示8 9: begin seg = 7'b0010000; dig = 4'b1110; end //显示9 10: begin seg = 7'b0001000; dig = 4'b1110; end //显示A 11: begin seg = 7'b0000011; dig = 4'b1011; end //显示B endcase endmodule ``` 这个代码中,我们使用case块来根据计数器的值选择对应的数码管显示内容。注意,这里我们只显示了0到B这12个数字和字母。 最后,我们需要将计数器和数码管控制器组合在一起,以实现完整的十二位十进制计数器及数码管显示。 以下是一个简单的Verilog HDL代码,用于实现这个系统: ``` module counter12_display( input clk, //时钟信号 input rst, //复位信号 output reg [6:0] seg, //数码管段选输出 output reg [3:0] dig //数码管位选输出 ); wire [11:0] count; //计数器输出 counter12 counter(clk, rst, count); seg_controller controller(count, seg, dig); endmodule ``` 这个代码中,我们使用wire声明了一个计数器输出信号count,并将它连接到了十二位十进制计数器和数码管控制器。最后,我们将数码管段选输出和位选输出作为模块的输出。 以上就是一个简单的十二位十进制计数器及数码管显示的设计,使用了Verilog HDL语言。希望可以帮到你!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值