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:
- If there’s only one point,print “YES”. And if there’re two,you need
to judge the distance. - 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");
}