版权声明:转载注明下出处就行了。 https://blog.csdn.net/LJD201724114126/article/details/83536487
题目链接:poj 3304
题目大意:给出n条线段两个端点的坐标,问所有线段投影到一条直线上,如果这些所有投影至少相交于一点就输出Yes!,否则输出No!。
解题思路:
如果存在L的话,能说明什么。。说明L的法线L’肯定能经过所有的线段
若存在一条直线L‘能经过所有线段,说明存在L’经过所有线段的两个端点。
直线肯定经过两个端点。
那么我们只要枚举两个端点P1P2,对每个直线P1P2 遍历所有线段i:1~N,用叉积<=0来判断线段的两个端点L1L2是否在P1P2的两侧,如果找到一组P1P2就能输出YES了
向量P和向量Q,假如 P*Q>0 ,P在Q的顺时针,P*Q<0,则P在Q的逆时针,P*Q=0,则P与Q共线。
(L1P1^L1P2 )*(L2P1^L2P2 )<=0 ^代表外积,如下图
注意:要判断重复点,即P1P2有可能重点,那么只要加判一下就好了。
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
struct point
{
double x,y;
point(){}
point(double _x,double _y){
x=_x;y=_y;
}
};
point operator + (point a,point b) {return point(a.x+b.x,a.y+b.y);}
point operator - (point a,point b) {return point(a.x-b.x,a.y-b.y);}
point operator * (point a,double p) { return point(a.x*p,a.y*p);}
point operator / (point a,double p){ return point(a.x/p,a.y/p);}
struct line{
point S,E;
line(){}
line(point _a,point _b){
S=_a;E=_b;
}
}segment[110];
bool operator < (const point &a,const point &b){
return a.x<b.x||(a.x==b.x&&a.y<b.y);
}
const double esp=1e-8;
int dcmp(double x){
if(fabs(x)<esp) return 0;
else return x<0?-1:1;
}
bool operator ==(const point &a,const point &b){
return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;
}
double Cross(point a,point b) { return a.x*b.y-a.y*b.x;}
double area2(point a,point b, point c) {return Cross(b-a,c-a);}
double Dot(point A,point B) { return A.x*B.x+A.y*B.y;}///2,点积,即是|a||b|*cos<a,b>,可用来判断角度的范围
double Length(point A) {return sqrt(Dot(A,A));} ///两点之间的距离
int n;
bool check(line A)
{
if(dcmp(Length(A.E-A.S))==0) return 0;
for(int i=0;i<n;i++) ///判断该直线A是否相交所有线段
{
if(dcmp(area2(segment[i].S,A.S,A.E))*dcmp(area2(segment[i].E,A.S,A.E))>0)
return false;
}
return true;
}
int main()
{
int ncase;
scanf("%d",&ncase);
double x1,y1,x2,y2;
while(ncase--)
{
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
segment[i]=line(point(x1,y1),point(x2,y2));
}
bool flag=false;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
///枚举两条线段i,j的某两个端点作为直线
if(check(line(segment[i].S,segment[j].S))||check(line(segment[i].S,segment[j].E))
||check(line(segment[i].E,segment[j].S))||check(line(segment[i].E,segment[j].E))){
flag=true;
break;
}
}
}
if(flag) puts("Yes!");
else puts("No!");
}
return 0;
}