2020牛客暑期多校训练营(第三场)C.Operation Love

2020牛客暑期多校训练营(第三场)C.Operation Love

题目链接

题目描述

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:
2020牛客暑期多校训练营(第三场)C.Operation Love_第1张图片

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

这题也是思维题,比赛时用的暴力判边,赛后我也看了别人的代码,有一个非常简单,就是直接判断两条最长边及其叉积,叉积的方向很明显决定了左右手,所以叉积是这道题的关键,两段代码都挂一下:
1.简便做法,直接找长为 9 9 9 和长为 8 8 8 的边,再判断两条边的叉积方向即可:

#include
using namespace std;
struct point{
    double x,y;
}p[20];
double eps=1e-5;
double Distance(point p1,point p2){
return (sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y)));
}
double cross(point a,point b,point c){
    return (a.x-c.x)*(b.y-c.y)-(a.y-c.y)*(b.x-c.x);
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        bool flag=0;
        for(int i=0;i<20;i++) scanf("%lf%lf",&p[i].x,&p[i].y);
        for(int i=0;i<20;i++){
            if(fabs(Distance(p[i],p[(i+1)%20])-9)<eps){
                if((cross(p[i],p[(i+2)%20],p[(i+1)%20])<0)^(fabs(Distance(p[(i+1)%20],p[(i+2)%20])-8)<eps)) flag=1;
            }
        }
        if(!flag) printf("right\n");
        else printf("left\n");
    }
    return 0;
}

2.暴力判边,记录右手掌的每一条边,求出给出点的每一条边,然后暴力比较即可,注意有个坑点就是如果左手掌逆时针输入的话边的长度就和顺时针的右手掌一样,所以也要计算一遍叉积,详见代码,AC代码如下:

#include 
using namespace std;
const double eps=1e-5;
struct point{
    double x,y;
}p1[20],p2[20],p3[20];
double e1[20],e2[20],e3[20];
double Distance(point p1,point p2){
return (sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y)));
}
double cross(point a,point b,point c){
    return (a.x-c.x)*(b.y-c.y)-(a.y-c.y)*(b.x-c.x);
}
bool judge(){
    for(int i=0;i<20;i++){//与右手掌的顺时针边比较
        int flag=0;
        for(int j=0;j<20;j++){
            if(fabs(e2[(j+i)%20]-e1[j])<eps) flag++;
        }
        if(flag==20){
            if(cross(p1[19],p1[1],p1[0])*cross(p2[i-1<0?19:i-1],p2[(i+1)%20],p2[i])>0) return 1;
        }
    }
    for(int i=0;i<20;i++){////与右手掌的逆时针边比较
        int flag=0;
        for(int j=0;j<20;j++){
            if(fabs(e3[(j+i)%20]-e1[j])<eps) flag++;
        }
        if(flag==20){
             if(cross(p1[19],p1[1],p1[0])*cross(p3[i-1<0?19:i-1],p3[(i+1)%20],p3[i])>0) return 1;
        }
    }
    return 0;
}

int main(){
    p2[0].x=1.000000,p2[0].y=0.000000;
    p2[1].x=10.000000,p2[1].y=0.000000;
    p2[2].x=10.000000,p2[2].y=8.000000;
    p2[3].x=9.000000,p2[3].y=8.000000;
    p2[4].x=9.000000,p2[4].y=5.000000;
    p2[5].x=8.000000,p2[5].y=5.000000;
    p2[6].x=8.000000,p2[6].y=10.000000;
    p2[7].x=7.000000,p2[7].y=10.000000;
    p2[8].x=7.000000,p2[8].y=5.000000;
    p2[9].x=6.000000,p2[9].y=5.000000;
    p2[10].x=6.000000,p2[10].y=10.000000;
    p2[11].x=5.000000,p2[11].y=10.000000;
    p2[12].x=5.000000,p2[12].y=5.000000;
    p2[13].x=4.000000,p2[13].y=5.000000;
    p2[14].x=4.000000,p2[14].y=10.000000;
    p2[15].x=3.000000,p2[15].y=10.000000;
    p2[16].x=3.000000,p2[16].y=3.000000;
    p2[17].x=2.000000,p2[17].y=3.000000;
    p2[18].x=2.000000,p2[18].y=6.000000;
    p2[19].x=1.000000,p2[19].y=6.000000;
    for(int i=0;i<20;i++){
        e2[i]=Distance(p2[i],p2[(i+1)%20]);
        if(i==0) p3[i]=p2[i];
        else p3[i]=p2[20-i];
    }
    for (int i=0;i<20;i++) e3[i]=Distance(p3[i],p3[(i+1)%20]);//记录右手掌的逆时针边
    int t;
    scanf("%d",&t);
    while(t--){
        for(int i=0;i<20;i++) scanf("%lf%lf",&p1[i].x,&p1[i].y);
        for(int i=0;i<20;i++) e1[i]=Distance(p1[i],p1[(i+1)%20]);
        if(judge()) printf("right\n"); 
        else printf("left\n");
     }
    return 0;
}

你可能感兴趣的:(计算几何,思维,牛客)