【计几】codeforces1017E 判断两凸包是否全等(凸包+kmp)

题目链接: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 }
View Code

猜你喜欢

转载自www.cnblogs.com/xiaobuxie/p/12240479.html