n很小,只有100.可以枚举任意两条线段的两个端点,叉积判断是否和其他所有线段相交。时间复杂度
O
(
n
3
)
O(n^{3})
O(n3)
证明:若有直线l与所有线段相交,则可保持l和所有线段相交,左右平移l到和某一个线段交于端点时无法在移动了,然后绕这个交点旋转,到转不动了,将会与另一线段交于一端点。
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#define ll long long
using namespace std;
const int maxn = 1e2+10;
const double EXP = 1e-6;
struct segment{
double x1,y1,x2,y2;
}s[maxn];
int T,n;
double dis(double x1,double y1,double x2,double y2){
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
double cross(double x1,double y1,double x2,double y2,double x,double y){
return (x2-x1)*(y-y1)-(x-x1)*(y2-y1);
}
bool judge(double x1,double y1,double x2,double y2){
if(dis(x1,y1,x2,y2)<EXP)return false;
for(int i=1;i<=n;i++){
if(cross(x1,y1,x2,y2,s[i].x1,s[i].y1)*
cross(x1,y1,x2,y2,s[i].x2,s[i].y2)>EXP)return false;
}
return true;
}
int main(){
scanf("%d",&T);
while(T--){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lf%lf%lf%lf",&s[i].x1,&s[i].y1,&s[i].x2,&s[i].y2);
}
if(n==1){cout<<"Yes!"<<endl;continue;}
bool flag=false;
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
if(judge(s[i].x1,s[i].y1,s[j].x1,s[j].y1)||
judge(s[i].x1,s[i].y1,s[j].x2,s[j].y2)||
judge(s[i].x2,s[i].y2,s[j].x1,s[j].y1)||
judge(s[i].x2,s[i].y2,s[j].x2,s[j].y2)){
flag=true;break;
}
}
if(flag)break;
}
if(flag)cout<<"Yes!"<<endl;
else cout<<"No!"<<endl;
}
return 0;
}