题目大意:给出n条线段两个端点的坐标,问所有线段投影到一条直线上,如果这些所有投影至少相交于一点就输出Yes!,否则输出No!。
解题思路:如果有存在这样的直线,过投影相交区域作直线的垂线,该垂线必定与每条线段相交,问题转化为问是否存在一条线和所有线段相交。
显然所求线段若存在,那么一定可以通过移动使其卡到2个端点上。
所以,枚举所有端点,判断该直线是否合法。
坑点:
1.同一条线段的2个端也需要枚举,因为可能所有线段共线
2.判断所枚举的直线是否退化为点。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#define ll long long
#define IOS {ios::sync_with_stdio(0);cin.tie(0);}
using namespace std;
const int N = 200;
const double eps=1e-8;
const double pi=acos(-1.0);
int sgn(double x){
if(fabs(x)<eps) return 0;
if(x<0) return -1;
else return 1;
}
struct P{
double x,y;
P(){}
P(double a,double b){x=a;y=b;}
P operator - (P b) const{
return P(x-b.x,y-b.y);
}
double operator ^ (P b) const{
return x*b.y-y*b.x;
}
double operator * (P b) const{
return x*b.x+y*b.y;
}
void transXY(double B){
double tx=x,ty=y;
x=tx*cos(B)-ty*sin(B);
y=tx*sin(B)-ty*cos(B);
}
}s[2*N];
struct L{
P s,e;
L(){}
L(P _s,P _e){
s = _s;e = _e;
}
}line[N];
bool L_inter_Seg(L l1,L l2){ //判断直线和线段是否相交
return sgn((l2.s-l1.e)^(l1.s-l1.e))*sgn((l2.e-l1.e)^(l1.s-l1.e))<=0;
}
int main(){
IOS;
int T;
cin>>T;
while(T --){
int n,i,j,k;
cin>>n;
for(i = 1;i <= n;i ++){
cin>>line[i].s.x>>line[i].s.y;
cin>>line[i].e.x>>line[i].e.y;
s[i*2-1] = line[i].s;
s[i*2] = line[i].e;
}
bool flag=0;
for(i = 1;i <= 2*n;i ++)
for(j = i+1;j <= 2*n;j ++){
L now(s[i],s[j]);
if(s[i].x==s[j].x&&s[i].y==s[j].y) continue;
for(k = 1;k <= n;k ++)
if(!L_inter_Seg(now,line[k])) break;
if(k==n+1) flag = 1;
}
if(flag)cout<<"Yes!";
else cout<<"No!";
cout<<endl;
}
return 0;
}
```