zoukankan      html  css  js  c++  java
  • ABC207:D

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

    题目

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

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

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

    思路

    前置知识

    已知坐标求角度

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

    绕原点旋转坐标变化

    高一以下学历慎入

    (A)坐标为((x,y)),((rcdot cos alpha , rcdot sin alpha)),则(cos alpha=frac{x}{r},sin alpha = frac{y}{r}),设(A)逆时针旋转(eta)得到(B),则(B(rcdot cos (alpha-eta) , rcdot sin (alpha-eta) ))

    [egin{align} rcdot cos(alpha -eta) &=rcdot (cosalphacdot cos eta+sin alpha cdot cos eta) \ &=rcdot (frac{x}{r} cdot cos eta+frac yr cdot sin eta) \ &=x cdot cos eta+y cdot sin eta\ end{align} ]

    同理,

    [egin{align} rcdot sin(alpha -eta) &=rcdot (sinalphacdot cos eta-cos alpha cdot sin eta) \ &=rcdot (frac yr cdot cos eta-frac xr cdot sin eta) \ &=y cdot cos eta-x cdot sin eta\ end{align} ]

    所以,用(x,y)表示(B)((x cdot cos eta+y cdot sin eta , y cdot cos eta-x cdot sin eta))

    二维平面点的重心

    定义(n)个点,坐标依次((x_i,y_i)),它们的重心为

    [(frac{ sum^n_{i=1}x_i} {n} , frac{ sum^n_{i=1}y_i} {n}) ]

    若每个点坐标变为((x_i+a,y_i+b)),则重心坐标变为:

    [(frac{ sum^n_{i=1}x_i} {n}+a , frac{ sum^n_{i=1}y_i} {n}+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;
    }
    
  • 相关阅读:
    基础数据补充
    购物车
    小数据池、深浅拷贝和集合
    列表、元组和range
    小数据池、深浅拷贝和集合练习
    字典
    字符串练习
    列表练习
    练习
    字典练习
  • 原文地址:https://www.cnblogs.com/dream1024/p/14961081.html
Copyright © 2011-2022 走看看