https://www.luogu.org/problemnew/show/P1355
判断一个点和三角形的位置关系,最简单的思路就是用向量。
首先排除掉和三角形顶点重合的情况。
把三角形设计成一个首尾相接的三个向量,从三个向量的起点连线到P点构成新向量,叉乘判断方向。二维向量叉乘(x1,y1)×(x2,y2)=(x1y2-x2y1),方向是右手螺旋。那么判断正负号就知道他们在向量的哪一侧了。
在三角形中的应该在三个向量的同侧。而不在三角形中的会有一个方向与另外两个不同。在三角形上的显然就是存在一个0。
上面的解法有一个bug,其实叉乘为0只是代表在直线上,判断在线段上还要加一次点乘。
顺便练习一波scanf,注意scanf读入double必须是%lf,要求scanf略去字符可以参考下方写法,注意换行符用空格略去。
#include<bits/stdc++.h> using namespace std; #define ll long long struct Vector{ double x,y; Vector(double xx=0.0,double yy=0.0){x=xx,y=yy;} Vector operator-(Vector v2){ return Vector(x-v2.x,y-v2.y); } bool operator==(Vector v2){ if(fabs(x-v2.x)<1e-8&&fabs(y-v2.y)<1e-8) return true; return false; } double dot(Vector v2){ return x*v2.x+y*v2.y; } double cross(Vector v2){ return x*v2.y-y*v2.x; } }; typedef Vector Point; int main(){ Point A,B,C,P; scanf("(%lf,%lf)",&A.x,&A.y); scanf(" (%lf,%lf)",&B.x,&B.y); scanf(" (%lf,%lf)",&C.x,&C.y); scanf(" (%lf,%lf)",&P.x,&P.y); if(A==P||B==P||C==P){ printf("4 "); return 0; } Vector a=C-B,b=A-C,c=B-A; Vector pa=P-B,pb=P-C,pc=P-A; double cross1=a.cross(pa); double cross2=b.cross(pb); double cross3=c.cross(pc); if(fabs(cross1)<1e-8){ //bug在这里,叉乘为0是在直线上而非线段上 //前面判断了在端点上的情况,所以现在只需要判断方向 Vector t1=pa,t2=pb; if(t1.dot(t2)<0) printf("3 "); else printf("2 "); return 0; } if(fabs(cross2)<1e-8){ //bug在这里,叉乘为0是在直线上而非线段上 //前面判断了在端点上的情况,所以现在只需要判断方向 Vector t1=pb,t2=pc; if(t1.dot(t2)<0) printf("3 "); else printf("2 "); return 0; } if(fabs(cross3)<1e-8){ //bug在这里,叉乘为0是在直线上而非线段上 //前面判断了在端点上的情况,所以现在只需要判断方向 Vector t1=pc,t2=pa; if(t1.dot(t2)<0) printf("3 "); else printf("2 "); return 0; } int flag1=cross1*cross2>0; int flag2=cross2*cross3>0; int flag3=cross3*cross1>0; if(flag1&&flag2&&flag3){ printf("1 "); return 0; } printf("2 "); }