这道题是求是否存在一条直线导致所有给定线段在这条直线上的投影是否有共同的交点,那么从这点做该条直线的垂线,一定能够交到所有的线段(根据投影的性质得到),所以问题转化成了能否找到一条直线穿过所有的线段,我们能够通过叉积判断一条线段和直线是否相交,那么我们可以枚举每两个端点组成的直线,因为凡是满足穿过所有线段的直线,一定可以通过旋转得到一个正好和至少有两个端点在直线上的临界状态.
注意判断端点距离极小时的情况,得到的叉积可能为0影响判断
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define eps 1e-8
#define MAX 207
using namespace std;
struct Point
{
double x,y;
Point ( ) : x(0) , y(0){}
Point ( double a , double b ) : x(a),y(b){}
};
struct Line
{
Point start,end;
};
double cross ( Point p , Point p1 , Point p2 )
{
return ( p.x - p2.x )*( p1.y - p2.y )-( p1.x - p2.x )*( p.y - p2.y);
}
bool intersect ( Line l , Point a , Point b )
{
if ( cross( l.start,a,b) * cross ( l.end,a,b) <= 0 )
return true;
else return false;
}
bool equal ( Point a , Point b )
{
if ( fabs(a.x-b.x)<eps && fabs(a.y-b.y)<eps ) return true;
else return false;
}
Point p[MAX];
Line l[MAX];
int n;
bool judge ( )
{
for ( int i = 1 ; i <= 2*n ; i++ )
for ( int j = 1 ; j <= 2*n ; j++ )
{
if ( equal(p[i],p[j])) continue;
int k;
for ( k = 1 ; k <= n ; k++ )
{
if ( !intersect ( l[k] , p[i] , p[j]))
break;
}
if ( k==n+1 ) return true;
}
return false;
}
int main ( )
{
int t;
scanf ( "%d" , &t );
while ( t-- )
{
scanf ( "%d" , &n );
for ( int i=1,j=1; j<=n; i++,j++ )
{
scanf ( "%lf%lf" , &p[i].x , &p[i].y );
l[j].start.x = p[i].x;
l[j].start.y = p[i].y;
i++;
scanf ( "%lf%lf" , &p[i].x , &p[i].y );
l[j].end.x = p[i].x;
l[j].end.y = p[i].y;
}
if ( judge ( ) ) puts ( "Yes!" );
else puts ( "No!" );
}
}