2200+专项:E. The Supersonic Rocket(凸包(去掉共线) KMP)

70 篇文章 1 订阅
30 篇文章 2 订阅

original: http://codeforces.com/problemset/problem/1017/E

question:

Give you two sets of points in 2D plane. For each set,you should process it’s convex hull. And in the end,you should judge whether they are isomorphic by rotating.

analyze:

In this question,you need to remove the middle points in one line(more than two points collinear),just like this:

for(int i=3;i<=n;i++){
    while(top>2&&dcmp(Cross(ans[top]-ans[top-1],p[i]-ans[top]))<=0)top--;
    ans[++top]=p[i];
    if(top>2&&dcmp(Cross(ans[top]-ans[top-1],ans[top-1]-ans[top-2]))==0)
    	ans[top-1]=ans[top],--top;
}

And after getting the convex hull,you could use KMP to judge.

By choosing adjacent three points,you can get three real numbers(their distances),and make a struct. So you can get n struct from a n-point convex hull .

And use KMP to judge whether one struct sequence is subsequence of the other(doubled).

note:

  1. If there’s only one point,print “YES”. And if there’re two,you need
    to judge the distance.
  2. The simple KMP isn’t enough, you ought to use path compression to avoid TLE.
#include<bits/stdc++.h>
using namespace std;
const double EPS=1e-6;
struct point{
    double x,y;
    point(){}
    point(double x,double y):x(x),y(y){}
};
point operator-(point a,point b){
    return point(a.x-b.x,a.y-b.y);
}
int dcmp(double x){
    return fabs(x)<EPS?0:(x>0?1:-1);
}
double Cross(point a,point b){
    return a.x*b.y-b.x*a.y;
}
double Distance(point a,point b){
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
point p[2][100009],ans[2][100009];
int n,m,top1,top2;
point Tmp;//选好的起点
bool cmp(point a,point b){
    double ans=Cross(a-Tmp,b-Tmp);
    if(dcmp(ans)==0)return dcmp(Distance(a,Tmp)-Distance(b,Tmp))<0;
    return ans>0;//表示a到b是逆时针转
}
void Graham(point p[],int n,point ans[],int &top){
    if(n<3)return;
    for(int i=2;i<=n;i++){
        if(p[i].y<p[1].y||(dcmp(p[i].y-p[1].y)==0&&p[i].x<p[1].x))
            swap(p[1],p[i]);
    }
    Tmp=p[1];
    sort(p+2,p+1+n,cmp);
    ans[1]=p[1],ans[2]=p[2],top=2;
    for(int i=3;i<=n;i++){
        while(top>2&&dcmp(Cross(ans[top]-ans[top-1],p[i]-ans[top]))<=0)top--;
        ans[++top]=p[i];
        if(top>2&&dcmp(Cross(ans[top]-ans[top-1],ans[top-1]-ans[top-2]))==0)ans[top-1]=ans[top],--top;
    }

}

struct node{
    double x,y,z;
    node(){}
    node(double x,double y,double z):x(x),y(y),z(z){}
    void out(){
        printf("(%.1f %.1f %.1f)\n",x,y,z);
    }
    bool operator==(const node &R)const{
        return dcmp(x-R.x)==0&&dcmp(y-R.y)==0&&dcmp(z-R.z)==0;
    }
    bool operator!=(const node &R)const{
        return !(*this==R);
    }
}e[100009],b[100009];
int fail[100009];
void KMP(int len){
    /*fail[1]=0;fail[2]=1;
    int i=1,j=1;
    while(i<=len&&j<=len){
        if(j==0||e[i]==e[j])fail[++i]=++j;
        else j=fail[j];
    }*/
    fail[1]=0;
    int i=1,j=0;
    while(i<=len){
        while(j&&e[i]!=e[j])j=fail[j];
        fail[++i]=++j;
        if(e[i]==e[j])fail[i]=fail[j];
    }
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%lf%lf",&p[0][i].x,&p[0][i].y);
    }
    for(int i=1;i<=m;i++){
        scanf("%lf%lf",&p[1][i].x,&p[1][i].y);
    }
    Graham(p[0],n,ans[0],top1);
    Graham(p[1],m,ans[1],top2);

    if(top1-top2)return 0*printf("NO\n");
    if(top1==1)return 0*printf("YES\n");
    if(top1==2){
        if(dcmp(Distance(ans[0][1],ans[0][2])-Distance(ans[1][1],ans[1][2]))==0)return 0*printf("YES\n");
        return 0*printf("NO\n");
    }
    for(int i=1;i<=top1;i++){
        int l=i-1,r=i+1;
        if(l==0)l=top1;
        if(r>top1)r=1;
        e[i]=node(Distance(ans[0][i],ans[0][l]),Distance(ans[0][i],ans[0][r]),Distance(ans[0][l],ans[0][r]));
        //e[i].out();
    }
    for(int i=1;i<=top2;i++){
        int l=i-1,r=i+1;
        if(l==0)l=top2;
        if(r>top2)r=1;
        b[i]=node(Distance(ans[1][i],ans[1][l]),Distance(ans[1][i],ans[1][r]),Distance(ans[1][l],ans[1][r]));
    }
    KMP(top1);
    int j=1;
    for(int i=1;i<=top2;i++){
        while(e[j]!=b[i]&&j)
            j=fail[j];
        if(j==top1){
            return 0*printf("YES\n");
        }
        j++;
    }
    for(int i=1;i<=top2;i++){
        while(e[j]!=b[i]&&j)j=fail[j];
        if(j==top1){
            return 0*printf("YES\n");
        }
        j++;
    }
    printf("NO\n");
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值