2020牛客暑期多校(三)
https://ac.nowcoder.com/acm/contest/5668
C Operation Love
题意
顺时针或逆时针地给一个旋转/平移过的手的图形的点,判断是左手还是右手。
思路
- 取底边和底边两旁的两个点。
- 判断是顺时针还是逆时针
- 判断边长为6的边在左边还是右边
- 得到结果,输出
知识点
判断顺时针还是逆时针:计算叉积。
三个连续点,顺时针还是逆时针,就是看是往哪边弯。
那么,以前两个点为向量,判断第三个点在向量左侧还是右侧。
注:向量才有左右哟(○` 3′○)
定义:
平面上三点P1(x1,y1)、P2(x2,y2)、P3(x3,y3)的面积量:
$\begin{vmatrix} 1 & 1 & 1 \\ x_1 & x_2 & x_3 \\ y_1 & y_2 & y_3 \notag \end{vmatrix}=(x_1-x_3)(y_2-y_3)-(y_1-y_3)(x_2-x_3)$
P1,P2,P3为逆时针时,值为正;顺时针:负;直线:0。
令矢量的起点为A,终点为B,判断的点为C,
若值为正数,则C在矢量AB的左侧;负数:右侧;0:AB上。
代码
#include<bits/stdc++.h> using namespace std; const int N=1e3+5; struct Point{ double x,y; }; Point p[22]; double diss[22]; int di[6]; double dis(Point a,Point b){ return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } Point getmid(Point a,Point b){ return {(a.x+b.x)/2,(a.y+b.y)/2}; } int getleft(Point qd,Point zd,Point c){ double res=(qd.x-c.x)*(zd.y-c.y)-(qd.y-c.y)*(zd.x-c.x); if(res>0) return 1; else return 0; } void sc(void){ for(int i=1;i<=20;i++){ scanf("%lf%lf",&p[i].x,&p[i].y); if(i!=1) diss[i]=dis(p[i],p[i-1]); if(9-0.00001<=diss[i]&&diss[i]<=9+0.00001) { if(i<20)di[1]=i+1; else di[1]=1; di[2]=i;di[3]=i-1; if(i>2) di[4]=i-2; else di[4]=20; } } diss[1]=dis(p[1],p[20]); if(9-0.00001<=diss[1]&&diss[1]<=9+0.00001) { di[1]=2;di[2]=1;di[3]=20;di[4]=19; } } int main(){ int t; scanf("%d",&t); while(t--){ sc(); Point md=getmid(p[di[2]],p[di[3]]); Point mg=getmid(p[di[1]],p[di[4]]); int left; if(getleft(md,mg,p[di[1]])) left=1; else left=4; if(left==1){ double disss=dis(p[di[left]],p[di[2]]); if(disss>=6-0.00001&&disss<=6+0.00001){ printf("right\n"); }else printf("left\n"); }else { double disss=dis(p[di[left]],p[di[3]]); if(disss>=6-0.00001&&disss<=6+0.00001){ printf("right\n"); }else printf("left\n"); } } }