链接 D - Congruence Points
题意
给出两个平面,每个平面上都有 n n n 个点,第一个平面上的点能否经过若干次整体平移或整体旋转后和第二个平面的点重合;
思路
首先求出由 n n n个点构成图形的重心,然后把两个平面中的重心都移到原点,这样就可以忽略平移的影响,只考虑旋转;
在求重心时,我们可以把每个点都× n n n,放缩减少精度误差;
然后从 n n n 个点中选取一个不是原点的点,和另一个平面中的点匹配去求角度,然后遍历第一个平面的所有点,看是否在第二平面有点与它重合即可;
AC代码
#include <bits/stdc++.h>
#define mes memset
#define mec memcpy
#define x first
#define y second
#define pb push_back
#define be(x) (x).begin(), (x).end()
#define cl(x) memset((x), 0, sizeof (x))
#define sz(x) (int)(x).size()
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double, double> PDD;
const double pi = acos(-1);
const double eps = 1e-8;
const int N = 1010;
const int null = 0x3f3f3f3f,INF = 1e9;
const ll mod = 998244353;
int n;
PDD p[2][N];
double get_len(PDD a)
{
return sqrt(a.x * a.x + a.y * a.y);
}
int dcmp(double x, double y)
{
if (fabs(x - y) < eps) return 0;
if (x < y) return -1;
return 1;
}
double get_angle(PDD a)
{
return atan2(a.y, a.x);
}
PDD rotate(PDD a, double angle)
{
return {a.x * cos(angle) + a.y * sin(angle), -a.x * sin(angle) + a.y * cos(angle)};
}
int main()
{
cin >> n;
for (int i = 0; i < 2; i ++)
{
double x = 0, y = 0;
for (int j = 1; j <= n; j ++)
{
cin >> p[i][j].x >> p[i][j].y;
p[i][j].x *= n;
p[i][j].y *= n;
x += p[i][j].x;
y += p[i][j].y;
}
x /= n, y /= n;
for (int j = 1; j <= n; j ++)
{
p[i][j].x -= x;
p[i][j].y -= y;
}
}
if (p[0][1].x == 0)
{
for (int i = 2; i <= n; i ++)
{
if (p[0][i].x != 0)
{
swap(p[0][i], p[0][1]);
break;
}
}
}
for (int i = 1; i <= n; i ++)
{
if (dcmp(get_len(p[0][1]), get_len(p[1][i])) != 0) continue;
double r = get_angle(p[0][1]) - get_angle(p[1][i]);
int res = 0;
for (int j = 1; j <= n; j ++)
{
PDD t = rotate(p[0][j], r);
for (int k = 1; k <= n; k ++)
{
if (!dcmp(t.x, p[1][k].x) && !dcmp(t.y, p[1][k].y))
{
res ++;
break;
}
}
}
if (res == n)
{
puts("Yes");
return 0;
}
}
puts("No");
}