题目链接:The Supersonic Rocket
题意
有两个点集,点的个数分别为 n n 和 ,问两个点集分别构成的凸包是否可以通过旋转、平移使得两个凸包完全重合。
输入
第一行包含两个整数 n,m (3≤n,m≤105) n , m ( 3 ≤ n , m ≤ 10 5 ) ,接下去 n n 行每行两个整数 ,表示第一个点集中每个点的坐标,最后 m m 行每行两个整数 ,表示第二个点集中每个点的坐标,其中 0≤xi,yi≤108 0 ≤ x i , y i ≤ 10 8 。
输出
如果可以通过旋转与平移使两个凸包完全重合,输出 YES Y E S ,否则输出 NO N O ,大小写任意。
样例
输入 |
---|
3 4 0 0 0 2 2 0 0 2 2 2 2 0 1 1 |
输出 |
YES |
提示 |
点集在平面直角坐标系上的位置为:![]() 将第一个点集旋转 180° 180 ° 后: ![]() 再将第二个点集平移 (−2,−2) ( − 2 , − 2 ) 后: ![]() |
输入 |
---|
3 4 0 0 0 2 2 0 0 2 2 2 2 0 0 0 |
输出 |
NO |
提示 |
不论如何平移旋转,两个凸包都不会重合。 |
题解
先分别跑出两个点集的凸包,判定两个凸包可以旋转平移重合的条件是:每条对应边的长度相等且对应角的大小相等,对应边直接求边长平方,对应角可以用叉积。将其中一个点集在凸包上所有点都复制到最后,让另一个凸包的所有点在这上面跑一遍 kmp k m p , kmp k m p 能够往后跑的条件就是对应边与对应角都相等。
过题代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <cstring>
#include <string>
#include <vector>
#include <list>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <bitset>
#include <algorithm>
#include <functional>
#include <iomanip>
using namespace std;
#define LL long long
const int maxn = 100000 + 100;
struct Point {
LL x, y;
Point() {}
Point(LL xx, LL yy) {
x = xx;
y = yy;
}
};
LL operator*(const Point &a, const Point &b) {
return a.x * b.x + a.y * b.y;
}
bool operator<(const Point &a, const Point &b) {
return a.x == b.x? a.y < b.y: a.x < b.x;
}
LL operator^(const Point &a, const Point &b) {
return a.x * b.y - a.y * b.x;
}
Point operator-(const Point &a, const Point &b) {
return Point(a.x - b.x, a.y - b.y);
}
struct Cross_len {
LL cross, len;
};
bool operator==(const Cross_len &a, const Cross_len &b) {
return a.cross == b.cross && a.len == b.len;
}
bool operator!=(const Cross_len &a, const Cross_len &b) {
return !(a == b);
}
int n[2], top[2];
Point point[2][maxn], sta[2][maxn << 1];
int Next[maxn];
Cross_len cross_len[2][maxn << 1];
void ConvexHull(Point *p, int n, int &top, Point *sta) {
top = 0;
sort(p + 1, p + 1 + n);
for(int i = 1; i <= n; ++i) {
while(top > 1 && ((sta[top - 1] - sta[top - 2]) ^ (p[i] - sta[top - 2])) <= 0) {
--top;
}
sta[top++] = p[i];
}
int ttop = top;
for(int i = n; i > 0; --i) {
while(top > ttop && ((sta[top - 1] - sta[top - 2]) ^ (p[i] - sta[top - 2])) <= 0) {
--top;
}
sta[top++] = p[i];
}
--top;
}
void Change_to_Cross_len(Point *p, int n, Cross_len *c) {
Point p0 = p[0];
for(int i = 0; i < n - 1; ++i) {
p[i] = p[i + 1] - p[i];
c[i].len = p[i] * p[i];
}
p[n - 1] = p0 - p[n - 1];
c[n - 1].len = p[n - 1] * p[n - 1];
for(int i = 0; i < n; ++i) {
c[i].cross = p[i] ^ p[(i + 1) % n];
}
}
void get_next(Cross_len *str, int n) {
int j = -1;
Next[0] = -1;
for(int i = 1; i < n; ++i) {
while(j != -1 && str[j + 1] != str[i]) {
j = Next[j];
}
if(str[i] == str[j + 1]) {
++j;
}
Next[i] = j;
}
}
bool kmp(Cross_len *str1, int n, Cross_len *str2, int m) {
int j = -1;
for(int i = 0; i < n; ++i) {
while(j != -1 && str1[i] != str2[j + 1]) {
j = Next[j];
}
if(str1[i] == str2[j + 1]) {
++j;
}
if(j == m - 1) {
return true;
}
}
return false;
}
int main() {
#ifdef LOCAL
freopen("test.txt", "r", stdin);
// freopen("test1.out", "w", stdout);
#endif // LOCAL
ios::sync_with_stdio(false);
while(scanf("%d%d", &n[0], &n[1]) != EOF) {
memset(point, 0, sizeof(point));
for(int i = 0; i < 2; ++i) {
for(int j = 1; j <= n[i]; ++j) {
scanf("%I64d%I64d", &point[i][j].x, &point[i][j].y);
}
ConvexHull(point[i], n[i], top[i], sta[i]);
if(i == 0) {
for(int j = 0; j < top[i]; ++j) {
sta[i][j + top[i]] = sta[i][j];
}
top[i] *= 2;
}
Change_to_Cross_len(sta[i], top[i], cross_len[i]);
}
get_next(cross_len[1], top[1]);
if(kmp(cross_len[0], top[0], cross_len[1], top[1])) {
printf("Yes\n");
} else {
printf("No\n");
}
}
return 0;
}