题意:有n条直线,求是否存在一条直线使得所有线段在这条直线上的投影有至少一个公共点。
方法:假设有一条直线满足题意,则必有所有的线段在这条直线上的投影交于一点,则过这点做这条直线的垂线,则这条垂线必定与所有的线段相交
反之,则假如有一条直线与所有的线段有交点,则做这条直线的垂线,那么这条直线与它的垂线的交点是所有线段投影与这条垂线的公共交点。
注意:1.线段与直线相交,线段在直线的两侧
2.如果两个点的距离小于10^-8则为一个点,少了超时;
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
#define eps 1e-8
struct Point{
double x,y;
}point[1005];
struct Line{
Point a,b;
}line[1005];
double cross(Point p0,Point p1,Point p2)
{
return (p0.x-p1.x)*(p2.y-p1.y)-(p2.x-p1.x)*(p0.y-p1.y);
}
int delcmp(double x)
{
if( fabs(x)<eps )
return 0;
return x>0?1:-1;
}
int intersect(Point p0,Point p1,Point p2,Point p3)
{
int d1=delcmp( cross(p0,p2,p3) );
int d2=delcmp( cross(p1,p2,p3) );
int d3=delcmp( cross(p2,p0,p1) );
int d4=delcmp( cross(p3,p0,p1) );
double d=cross( p2,p0,p1 )*cross( p3,p0,p1 ); //线段在直线的两侧;
if( d<=0 ) return 1;
//if( d1*d2<=0&&d3*d4<=0 )
// return 1;
return 0;
}
int equle(Point p0,Point p1) //少了超时
{
double d=sqrt( (p0.x-p1.x)*(p0.x-p1.x)+(p0.y-p1.y)*(p0.y-p1.y) );
if( d<eps )
return 0;
return 1;
}
int main()
{
int T;
scanf("%d",&T);
while( T-- )
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
double x1,y1,x2,y2;
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
point[i].x=x1;point[i].y=y1;
point[n+i].x=x2;point[n+i].y=y2;
line[i].a.x=x1;line[i].a.y=y1;
line[i].b.x=x2;line[i].b.y=y2;
}
int flag=0;
for(int i=1;i<=2*n&&!flag;i++)
{
for(int j=i+1;j<=2*n&&!flag;j++)
{
int sum=0;
if( equle( point[i],point[j] ) ){ //不能少这个判断条件
for(int k=1;k<=n;k++)
{
if( intersect( point[i],point[j],line[k].a,line[k].b ) )
{
sum++;
}
}
}
if( sum==n )
flag=1;
}
}
if( flag )
printf("Yes!\n");
else
printf("No!\n");
}
return 0;
}