Codeforces-1017E:The Supersonic Rocket(凸包+KMP)

E. The Supersonic Rocket
time limit per test1 second
memory limit per test256 megabytes
inputstandard input
outputstandard output
After the war, the supersonic rocket became the most common public transportation.

Each supersonic rocket consists of two “engines”. Each engine is a set of “power sources”. The first engine has n power sources, and the second one has m power sources. A power source can be described as a point ( x i , y i ) on a 2-D plane. All points in each engine are different.

You can manipulate each engine separately. There are two operations that you can do with each engine. You can do each operation as many times as you want.

For every power source as a whole in that engine: ( x i , y i ) becomes ( x i + a , y i + b ) , a and b can be any real numbers. In other words, all power sources will be shifted.
For every power source as a whole in that engine: ( x i , y i ) becomes ( x i c o s θ y i s i n θ , x i s i n θ + y i c o s θ ) , θ can be any real number. In other words, all power sources will be rotated.

The engines work as follows: after the two engines are powered, their power sources are being combined (here power sources of different engines may coincide). If two power sources A ( x a , y a ) and B ( x b , y b ) exist, then for all real number k that 0 < k < 1 a new power source will be created C k ( k x a + ( 1 k ) x b , k y a + ( 1 k ) y b ) . Then, this procedure will be repeated again with all new and old power sources. After that, the “power field” from all power sources will be generated (can be considered as an infinite set of all power sources occurred).

A supersonic rocket is “safe” if and only if after you manipulate the engines, destroying any power source and then power the engine, the power field generated won’t be changed (comparing to the situation where no power source erased). Two power fields are considered the same if and only if any power source in one field belongs to the other one as well.

Given a supersonic rocket, check whether it is safe or not.

Input
The first line contains two integers n , m ( 3 n , m 10 5 ) — the number of power sources in each engine.

Each of the next n lines contains two integers x i and y i ( 0 x i , y i 10 8 ) — the coordinates of the i-th power source in the first engine.

Each of the next m lines contains two integers x i and y i ( 0 x i , y i 10 8 ) — the coordinates of the i-th power source in the second engine.

It is guaranteed that there are no two or more power sources that are located in the same point in each engine.

Output
Print “YES” if the supersonic rocket is safe, otherwise “NO”.

You can print each letter in an arbitrary case (upper or lower).

Examples
input
3 4
0 0
0 2
2 0
0 2
2 2
2 0
1 1
output
YES
input
3 4
0 0
0 2
2 0
0 2
2 2
2 0
0 0
output
NO

题意:给定2个点集A,B。保证A,B中没有三点以上共线的情况,问A,B的凸包是否相同
思路:求出A,B的凸包后,对于每个凸包上的点 i ,求出 ( i 1 , i , i + 1 ) 三点构成的三角形的三边长度,以此为匹配信息对2个凸包进行KMP匹配。

#include<bits/stdc++.h>
using namespace std;
const int MAX=1e5+10;
const int MOD=1e9+7;
typedef long long ll;
struct Point
{
    ll x,y;
    void show(){cout<<"("<<x<<","<<y<<")"<<endl;}
}a[MAX],b[MAX],A[MAX],B[MAX];
Point operator+(Point A,Point B){return (Point){A.x+B.x,A.y+B.y};}        //向量A+B
Point operator-(Point A,Point B){return (Point){A.x-B.x,A.y-B.y};}        //向量A-B
Point operator*(Point A,ll B){return (Point){A.x*B,A.y*B};}           //向量A*B
Point operator/(Point A,ll B){return (Point){A.x/B,A.y/B};}           //向量A/B
ll operator*(Point A,Point B){return A.x*B.x+A.y*B.y;}            //向量A B的点积
ll operator^(Point A,Point B){return A.x*B.y-A.y*B.x;}            //向量A B的叉积
ll cross(Point A,Point B){return A.x*B.y-A.y*B.x;}                //向量A B的叉积
double dis(Point A,Point B){return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));}//A B两点的距离
ll dis2(Point A,Point B){return (A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y);}     //A B两点的距离的平方
int cmp(const Point& x,const Point& y)
{
    if(x.x==y.x)return x.y<=y.y;
    return x.x<y.x;
}
int Tu(Point *p,int n,Point *ch)//求凸包
{
    sort(p,p+n,cmp);
    int m=0;
    for(int i=0;i<n;i++)
    {
        while(m>1&&cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0)m--;
        ch[m++]=p[i];
    }
    int k=m;
    for(int i=n-2;i>=0;i--)
    {
        while(m>k&&cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0)m--;
        ch[m++]=p[i];
    }
    if(n>1)m--;
    return m;
}
struct lenka
{
    ll a,b,c;
    int operator==(const lenka& d)const{return d.a==a&&d.b==b&&d.c==c;}
    int operator!=(const lenka& d)const{return d.a!=a||d.b!=b||d.c!=c;}
};
vector<lenka>PA,PB;
int f[MAX];
int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=0;i<n;i++)scanf("%lld%lld",&a[i].x,&a[i].y);
    for(int i=0;i<m;i++)scanf("%lld%lld",&b[i].x,&b[i].y);
    n=Tu(a,n,A);
    m=Tu(b,m,B);
    if(n!=m)puts("NO");
    else
    {
        for(int i=0;i<n;i++)PA.push_back((lenka){dis2(A[(i-1+n)%n],A[i]),dis2(A[i],A[(i+1)%n]),dis2(A[(i-1+n)%n],A[(i+1)%n])});
        for(int i=0;i<m;i++)PB.push_back((lenka){dis2(B[(i-1+m)%m],B[i]),dis2(B[i],B[(i+1)%m]),dis2(B[(i-1+m)%m],B[(i+1)%m])});
        for(int i=0;i<n;i++)PA.push_back(PA[i]);//在末尾复制一遍
        f[0]=f[1]=0;
        for(int i=1;i<m;i++)//next数组
        {
            int j=f[i];
            while(j&&PB[i]!=PB[j])j=f[j];
            f[i+1]=(PB[i]==PB[j]?j+1:0);
        }
        for(int i=0,j=0;i<PA.size();i++)//匹配
        {
            while(j&&PA[i]!=PB[j])j=f[j];
            if(PA[i]==PB[j])j++;
            if(j==m)
            {
                puts("YES");
                return 0;
            }
        }
        puts("NO");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Mitsuha_/article/details/81530923