C Operation Love(2020牛客暑期多校训练营(第三场))(计算几何)

C Operation Love(2020牛客暑期多校训练营(第三场))(计算几何)

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
judge:牛客

题目描述

Alice is a beauty in a robot society. So many robots want to marry her. Alice determines to marry a robot who can solve the following puzzle:

Firstly, the shape of Alice’s right palm is as follow:

在这里插入图片描述

And the shape of Alice’s left palm is symmetrical to her right palm.

In this puzzle, Alice will give the challenger many handprints of her palm. The challenger must correctly tell Alice each handprint is her left palm or right palm. Notice that the handprint of Alice’s palm is given by its 2D plane coordinates in clockwise or counterclockwise order. And The shape may be rotated and translated. But the shape won’t be zoomed in nor be zoomed out.

Although you are not a robot, you are interested in solving puzzles. Please try to solve this puzzle.

输入描述:

The first line contains one integer t ( 1 ≤ t ≤ 1 0 3 ) t (1 \le t \le 10^3) t(1t103) — the number of handprints in Alice’s puzzle.

Each handprint is described by a simple polygon composed of 20 points. Each point in this polygon will be given in clockwise or counterclockwise order. Each line contains two real numbers with exactly six digits after the decimal point, representing the coordinate of a point. So a handprint is composed of 20 lines in the input.

All values of coordinate in the input is in the range [-1000.0000000, 1000.000000].

输出描述:

For each footprint of palm, print a line contains “right” or “left”, indicating the footprint is the right palm or the left palm respectively.

示例1

输入

2
1.000000 0.000000
10.000000 0.000000
10.000000 8.000000
9.000000 8.000000
9.000000 5.000000
8.000000 5.000000
8.000000 10.000000
7.000000 10.000000
7.000000 5.000000
6.000000 5.000000
6.000000 10.000000
5.000000 10.000000
5.000000 5.000000
4.000000 5.000000
4.000000 10.000000
3.000000 10.000000
3.000000 3.000000
2.000000 3.000000
2.000000 6.000000
1.000000 6.000000
-1.000123 0.000000
-10.000123 0.000000
-10.000123 8.000000
-9.000123 8.000000
-9.000123 5.000000
-8.000123 5.000000
-8.000123 10.000000
-7.000123 10.000000
-7.000123 5.000000
-6.000123 5.000000
-6.000123 10.000000
-5.000123 10.000000
-5.000123 5.000000
-4.000123 5.000000
-4.000123 10.000000
-3.000123 10.000000
-3.000123 3.000000
-2.000123 3.000000
-2.000123 6.000000
-1.000123 6.000000

输出

right
left

示例2

输入

1
19.471068 -6.709056
13.814214 -1.052201
13.107107 -1.759308
15.228427 -3.880629
14.521320 -4.587735
10.985786 -1.052201
10.278680 -1.759308
13.814214 -5.294842
13.107107 -6.001949
9.571573 -2.466415
8.864466 -3.173522
12.400000 -6.709056
11.692893 -7.416162
8.157359 -3.880629
7.450253 -4.587735
12.400000 -9.537483
11.692893 -10.244590
9.571573 -8.123269
8.864466 -8.830376
13.107107 -13.073017

输出

right

说明

The handprint of example 2 is as follows:
在这里插入图片描述

It obviously is the right palm.

题解

首先需要找到个有效的特征来判断左右手,我发现手印中的大拇指和小拇指的长度是不同的,即样例中的(1,6)-(1,0)和(10,8)-(10,0),他们两个一个长度是6,另一个长度是8,而且6和8都是唯一出现的长度。然后从大拇指往小拇指方向画一段弧线((1,6)->(1,0)->(10,0))发现是逆时针,说明是右手,否则是左手。

那么怎么找到这一段弧线在数组中的位置呢?

首先有一个长度比较特殊,那就是手指的宽度,为1.
我们在数组中找到1的位置后一直向手指边缘逼近就得到了手腕部分的四个点,存入b数组。然后根据大拇指和小拇指的长度判断点的顺序是从大拇指到小拇指还是从小拇指到大拇指。若为小拇指到大拇指,反转一下b数组即可。

代码

#include <bits/stdc++.h>
#define _for(i, a) for (register int i = 0, lennn = (a); i < lennn; ++i)
#define _rep(i, a, b) for (register int i = (a), lennn = (b); i <= lennn; ++i)
using namespace std;
typedef long long LL;
const int maxn = 100005;
const double eps = 1e-5;

typedef struct poi {
    
    
    double x, y;
    poi() {
    
    }
    poi(double x, double y) : x(x), y(y) {
    
    }
    void inp() {
    
     scanf("%lf%lf", &x, &y); }
    poi operator+(poi tem) {
    
     return poi(x + tem.x, y + tem.y); }  //点/向量 相加
    poi operator-(poi tem) {
    
     return poi(x - tem.x, y - tem.y); }
    poi operator*(double tem) {
    
     return poi(x * tem, y * tem); }
    double operator*(poi tem) {
    
     return x * tem.x + y * tem.y; }  //点积
    double operator^(poi tem) {
    
     return x * tem.y - y * tem.x; }  //叉积
} Vector;

double dist(poi a, poi b) {
    
      //两点距离
    return sqrt((b - a) * (b - a));
}

double xmult(poi p0, poi p1, poi p2) {
    
      // p0p1 X p0p2
    return (p1 - p0) ^ (p2 - p0);
}

bool equ(double a, double b) {
    
    
    return fabs(a - b) < eps;
}

vector<poi> a;
int n = 20;
poi b[4];

void getlr() {
    
    
    int l;
    _for(i, n) {
    
    
        if (equ(dist(a[i], a[(i + n - 1) % n]), 1)) {
    
    
            for (l = i; equ(dist(a[l], a[(l + n - 1) % n]), 1); l += 2, l %= n);
            l += n - 2, l %= n;
            _for(j, 4) b[j] = a[(l + j) % n];
            return;
        }
    }
}

void sol() {
    
    
    a.resize(n);
    _for(i, n) a[i].inp();
    getlr();
    if (dist(b[0], b[1]) > dist(b[2], b[3])) reverse(b, b + 4);
    double cr = xmult(b[0], b[1], b[2]);  //向量叉积
    if (cr > 0) cout << "right\n";
    else cout << "left\n";
}

int main() {
    
    
    int T;
    while (cin >> T) {
    
    
        _for(i, T) {
    
     sol(); }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_42856843/article/details/107436392