zoukankan      html  css  js  c++  java
  • Codeforces 1299B Aerodynamic

    Description

    描述

    给定一个由 $n$ 个点组成的严格凸多边形。你要将这个图形平移 $n$ 次,每次将一个顶点与原点 $(0,0)$ 重合。请判断这 $n$ 个平移后的多边形的并是否与原图形相似。

    输入

    第一行为一个正整数 $n$($3 le n le 10^5$)。

    接下来 $n$ 行,每行两个正整数 $x_i, y_i$($|x_i|, |y_i| le 10^9$),表示一个顶点。

    在读入中,保证输入的点按逆时针顺序排列,形成严格凸多边形。

    输出

    一行一个 YESNO

    样例

    输入1

    4
    1 0
    4 1
    3 4
    0 3

    输出1

    YES

    输入2

    3
    100 86
    50 0
    150 0

    输出2

    NO

    输入3

    8
    0 0
    1 0
    2 1
    3 3
    4 6
    3 6
    2 5
    1 3

    输出3

    YES

    解释

    样例2:

    剩下两个见 Solution。

    Solution

    致和我一样没写过计算几何的人……

    前置知识:闵可夫斯基和

    「闵可夫斯基和」是两个欧几里得空间的点集的和,也称为这两个空间的「膨胀集」,以德国数学家闵可夫斯基命名。点集 $A$ 与 $B$ 的闵可夫斯基和被定义为:
    $$ A+B = { a+b ~|~ a in A, b in B} $$
    例如,平面上有两个三角形,其坐标分别为 $A={(1,0),(0,1),(0,-1)}$ 及 $B={(0,0),(1,1),(1,1)}$ ,则其闵可夫斯基和为 $A + B = {(1, 0), (2, 1), (2,1), (0, 1), (1, 2), (1, 0), (0,1), (1, 0), (1,2)}$。

    通俗一点,从原点向图形 $A$ 内部的每一个点做向量,将图形 $B$ 沿每个向量移动,所有的最终位置的并便是闵可夫斯基和(具有交换律)。

    现在题目已经给了我们一个点集,就叫做 $S$ 吧。

    对于 $(x, y) in S$,我们要把它给平移到 $(0, 0)$ 去,就是要走一个 $(-x, -y)$,所有的在一起,便是 $-S$ 了。

    然后我们发现,我们恰好是想要 从原点向图形 $-S$ 内部的每一个点做向量,将图形 $S$ 沿每个向量移动,所有的最终位置的并 这个图形,它正好就是 $S$ 与 $-S$ 的闵可夫斯基和!

    然后呢,就可以爆干了。

    当然这个做法不香,需要继续分析。

    正常求一定是 $2n$ 条边,所以有边共线。然后我们发现,与 $S$ 相似的答案多边形,与 $S$ 的相似比恰好为 $2$!

    这从样例中很容易看出来。

    样例1:

    样例3:

    从图中很明显可以看出来,临边相等且共线,而且它来自 两个相邻多边形的同一条边,而这次的平移取决于 它对面的那条边

    • 不重合,说明对边与它相等;
    • 共线,说明对边与它平行。

    所以,这题就是让我们判断,这个图形是否 中心对称

    于是检查对应点连线的中点是否重合就行了。

    时间复杂度 $mathcal O(n)$。

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 1e5 + 5;
    const double EPS = 1e-10;
    double x[N], y[N];
    int main()
    {
    	ios::sync_with_stdio(false);
    	int n;
    	cin >> n;
    	for(int i = 1; i <= n; i++) cin >> x[i] >> y[i];
    	if(n & 1) { cout << "NO
    "; return 0; }
    	int mid = n >> 1;
    	double px = (x[1] + x[mid + 1]) / 2.0;
    	double py = (y[1] + y[mid + 1]) / 2.0;
    	bool ok = true;
    	for(int i = 2; i <= mid; i++)
    	{
    		double kx = (x[i] + x[mid + i]) / 2.0;
    		double ky = (y[i] + y[mid + i]) / 2.0;
    		if(fabs(px - kx) >= EPS || fabs(py - ky) >= EPS) ok = false;
    	}
    	if(ok) cout << "YES
    ";
    	else cout << "NO
    ";
    	return 0;
    }
  • 相关阅读:
    Android MVP架构分析
    JavaEE基本了解
    学习面试题Day09
    使用反射来实现简单工厂模式
    Android Material Design简单使用
    c语言 找最小值
    c++ 计算指定半径圆的面积
    c++ 字符串拷贝以及合并
    python yaml文件读写
    python 列表元素替换以及删除
  • 原文地址:https://www.cnblogs.com/syksykCCC/p/CF1299B.html
Copyright © 2011-2022 走看看