ABC207:D - Congruence Points #几何# #数学#


ABC207:D - Congruence Points #几何# #数学#

题目

https://atcoder.jp/contests/abc207/tasks/abc207_d

大意:给定两个二维平面,各有 n n n个点,问,第一个平面上的点经过若干次整体平移或整体旋转(任意角度),能否和第二个平面的点重合

横纵坐标范围: [ − 10 , 10 ] [-10,10] [10,10], n n n范围: [ 1 , 100 ] [1,100] [1,100],均为整数

思路

前置知识

已知坐标求角度

坐标为 ( x , y ) (x,y) (x,y)调用atan2(y,x)可求得 (该点与原点连线) 与 x x x轴所成角

绕原点旋转坐标变化

高一以下学历慎入

A A A坐标为 ( x , y ) (x,y) (x,y), ( r ⋅ cos ⁡ α ,   r ⋅ sin ⁡ α ) (r\cdot \cos \alpha , \ r\cdot \sin \alpha) (rcosα, rsinα),则 cos ⁡ α = x r , sin ⁡ α = y r \cos \alpha=\frac{x}{r},\sin \alpha = \frac{y}{r} cosα=rx,sinα=ry,设 A A A逆时针旋转 β \beta β得到 B B B,则 B ( r ⋅ cos ⁡ ( α − β ) ,   r ⋅ sin ⁡ ( α − β )   ) B(r\cdot \cos (\alpha-\beta) , \ r\cdot \sin (\alpha-\beta)\ ) B(rcos(αβ), rsin(αβ) )
{ r ⋅ cos ⁡ ( α − β ) = r ⋅ ( cos ⁡ α ⋅ cos ⁡ β + sin ⁡ α ⋅ cos ⁡ β ) = r ⋅ ( x r ⋅ cos ⁡ β + y r ⋅ sin ⁡ β ) = x ⋅ cos ⁡ β + y ⋅ sin ⁡ β \begin{cases} r\cdot \cos(\alpha -\beta) &=r\cdot (\cos\alpha\cdot \cos \beta+\sin \alpha \cdot \cos \beta) \\ &=r\cdot (\frac{x}{r} \cdot \cos \beta+\frac yr \cdot \sin \beta) \\ &=x \cdot \cos \beta+y \cdot \sin \beta\\ \end{cases} rcos(αβ)=r(cosαcosβ+sinαcosβ)=r(rxcosβ+rysinβ)=xcosβ+ysinβ
同理,
{ r ⋅ sin ⁡ ( α − β ) = r ⋅ ( sin ⁡ α ⋅ cos ⁡ β − cos ⁡ α ⋅ sin ⁡ β ) = r ⋅ ( y r ⋅ cos ⁡ β − x r ⋅ sin ⁡ β ) = y ⋅ cos ⁡ β − x ⋅ sin ⁡ β \begin{cases} r\cdot \sin(\alpha -\beta) &=r\cdot (\sin\alpha\cdot \cos \beta-\cos \alpha \cdot \sin \beta) \\ &=r\cdot (\frac yr \cdot \cos \beta-\frac xr \cdot \sin \beta) \\ &=y \cdot \cos \beta-x \cdot \sin \beta\\ \end{cases} rsin(αβ)=r(sinαcosβcosαsinβ)=r(rycosβrxsinβ)=ycosβxsinβ
所以,用 x , y x,y x,y表示 B B B ( x ⋅ cos ⁡ β + y ⋅ sin ⁡ β   ,   y ⋅ cos ⁡ β − x ⋅ sin ⁡ β ) (x \cdot \cos \beta+y \cdot \sin \beta\ ,\ y \cdot \cos \beta-x \cdot \sin \beta) (xcosβ+ysinβ , ycosβxsinβ)

二维平面点的重心

定义 n n n个点,坐标依次 ( x i , y i ) (x_i,y_i) (xi,yi),它们的重心为
( ∑ i = 1 n x i n , ∑ i = 1 n y i n ) (\frac{ \sum^n_{i=1}x_i} {n} , \frac{ \sum^n_{i=1}y_i} {n}) (ni=1nxi,ni=1nyi)
若每个点坐标变为 ( x i + a , y i + b ) (x_i+a,y_i+b) (xi+a,yi+b),则重心坐标变为:
( ∑ i = 1 n x i n + a , ∑ i = 1 n y i n + b ) (\frac{ \sum^n_{i=1}x_i} {n}+a , \frac{ \sum^n_{i=1}y_i} {n}+b) (ni=1nxi+a,ni=1nyi+b)

正式思路

我们可以通过平移,将两个平面的点的重心都放到原点上.这样,我们就不用考虑原题平移的问题了.

所以,我们只需判断是否旋转重合,复杂度要求不高,直接枚举对应点即可

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
#define N 110
#define eps 1e-6
#define sqr(_) ((_) * (_))
bool equ(double _ , double __) {return fabs((_) - (__)) < eps;}
int n;
double a[N] , b[N] , c[N] , d[N];

void input(double *x , double *y) {
	double gx , gy;
	gx = gy = 0;
	for(int i = 1 ; i <= n ; i++) {
		cin >> x[i] >> y[i];
		gx += x[i] , gy += y[i];
	}
	gx /= (double)n , gy /= (double)n;
	
	for(int i = 1 ; i <= n ; i++) {
		x[i] -= gx , y[i] -= gy;//平移
	}
}
int main() {
	cin >> n;
	input(a , b);
	input(c , d);
	
	for(int i = 1 ; i <= n ; i++)//必须保证(a[1],b[1])不在原点(否则角度为0,无意义)
		if(a[i] != 0 || b[i] != 0) {
			swap(a[1] , a[i]);
			swap(b[1] , b[i]);
			break;
		}
	
	for(int i = 1 ; i <= n ; i++) {
		if(equ(sqr(a[1]) + sqr(b[1]) , sqr(c[i]) + sqr(d[i])) == false)	continue;//若A能绕原点旋转B,它们到原点的距离一定相等
		double angle = atan2(b[1] , a[1]) - atan2(d[i] , c[i]);//旋转角
		
		int cnt = 0;
		for(int j = 1 ; j <= n ; j++) {
			double x , y;
			x = a[j] * cos(angle) + b[j] * sin(angle);//旋转变换
			y = b[j] * cos(angle) - a[j] * sin(angle);
			for(int k = 1 ; k <= n ; k++) {
				if(equ(x , c[k]) && equ(y , d[k]))
					++cnt;//没有重合点,直接这样就可以了
			}
		}
		if(cnt == n) {
			puts("Yes");
			return 0;
		}
	}
	puts("No");
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值