题目链接:https://codeforces.com/problemset/problem/1017/E
题意:判断两个凸包是否能够通过平移和旋转使得两凸包重合。也就是判断两凸包是否全等。
先求凸包(没有三点共线那种),然后如果两者点数不同则不全等。
然后我们把两个凸包变成两个序列:边——角——边....的序列。然后两凸包全等当且仅当两个序列一致。那我们把第一个序列扩展一倍,第二个序列求kmp,然后第二个序列在第一个序列跑kmp即可。
细节:
1、由于是整点,边存边长平方,角存点乘,所以序列都是整数。
2、角度都存正角,也就是逆时针存角,然后不能用叉乘,因为角度都在0 ——180之间,所以直接用点乘,点乘同则代表角度同。(第55个点就是这里卡了)
果然还是角度判断正负用叉乘,大小用点乘啊。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N = 1e5+9; 5 struct Point{ 6 ll x,y; 7 bool operator < (const Point& b)const{ 8 if( x == b.x ) return y < b.y; 9 return x < b.x; 10 } 11 }pn[N],pm[N],ch[N]; 12 vector<ll> an,am; 13 int nex[N<<1]; 14 ll cross(Point a,Point b,Point c){ 15 return (b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y); 16 } 17 ll dot(Point a,Point b,Point c){ 18 return (b.x - a.x) * (c.x -a.x) + (b.y - a.y) * (c.y - a.y); 19 } 20 ll dis(Point a,Point b){ 21 return (b.x - a.x) * (b.x - a.x) + (b.y - a.y) * (b.y - a.y); 22 } 23 void Andrew(Point p[],int n,vector<ll>& a){ 24 sort(p,p+n); 25 int m = 0; 26 for(int i = 0;i<n;++i){ 27 while( m > 1 && cross(ch[m-2],p[i],ch[m-1]) >= 0 ) --m; 28 ch[m++] = p[i]; 29 } 30 int k = m; 31 for(int i = n-2;i>=0;--i){ 32 while( m>k && cross(ch[m-2],p[i],ch[m-1]) >= 0 ) --m; 33 ch[m++] = p[i]; 34 } 35 if(n>1) --m; 36 ch[m] = ch[0]; ch[m+1] = ch[1]; 37 for(int i = 0;i<m;++i){ 38 a.push_back( dis(ch[i],ch[i+1]) ); 39 a.push_back( dot(ch[i+1],ch[i+2],ch[i]) ); 40 } 41 } 42 void getnex(vector<ll> a){ 43 nex[0] = -1; 44 int i = 0,j = -1; 45 int n = a.size(); 46 while( i < n){ 47 if( j== -1 || a[i] == a[j]) nex[ ++i ] = ++j; 48 else j = nex[j]; 49 } 50 } 51 bool kmp(vector<ll> an,vector<ll> am){ 52 int n = an.size() , m = am.size(); 53 int i = 0, j = 0; 54 for(;i<n;){ 55 if( j == -1 || am[j] == an[i]){ 56 ++i; ++j; 57 if( j == m ) return 1; 58 } 59 else j = nex[j]; 60 } 61 return 0; 62 } 63 int main(){ 64 int n,m; scanf("%d %d",&n,&m); 65 for(int i = 0;i<n;++i) scanf("%lld %lld",&pn[i].x,&pn[i].y); 66 for(int i = 0;i<m;++i) scanf("%lld %lld",&pm[i].x,&pm[i].y); 67 Andrew(pn,n,an); 68 Andrew(pm,m,am); 69 if(an.size() != am.size()){ 70 puts("NO"); 71 return 0; 72 } 73 int num = an.size(); 74 for(int i = 0;i<num; ++i) an.push_back( an[i] ); 75 76 getnex(am); 77 if(kmp(an,am)) puts("YES"); 78 else puts("NO"); 79 return 0; 80 }