题目链接:Segments
思路
题目要求一条直线,使得所有线段在该直线上的投影至少有一个公共点。
多画几个图,可以发现,问题实际转化了找到一条直线,使得与所有线段相交。
给出来的点肯定都是有用的,猜一猜就知道要在所有线段的端点中枚举两个点, 连成一条直线,判断其它线段是否与该直线相交即可。
(简单证明:假设有一条直线A,与线段B线段C分别交与2点,此时我们可以通过恰当的旋转直线,将每条线段的其中一个端点作为交点,本题即假设已存在这样一条直线已与2条线段相交,然后去枚举其它线段判断相交即可)
直线和线段相交判断
//`直线和线段相交判断`
//`-*this line -v seg`
//`2 规范相交`
//`1 非规范相交`
//`0 不相交`
int linecrossseg(Line v) {
int d1 = sgn((e - s) ^ (v.s - s));
int d2 = sgn((e - s) ^ (v.e - s));
if ((d1 ^ d2) == -2) return 2;
return (d1 == 0 || d2 == 0);
}
主函数
int n;
bool check(Line t){
for(int k=1;k<=n;k++){
if(t.linecrossseg(line[k])==0) return false;
}
return true;
}
int main(){
int t;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i=1;i<=n;i++){
double x1,y1,x2,y2;
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
line[i].s.x=x1; line[i].s.y=y1;
line[i].e.x=x2; line[i].e.y=y2;
}
bool isok=false;
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){
Line t1,t2,t3,t4;
t1.s=line[i].s; t1.e=line[j].s;
t2.s=line[i].s; t2.e=line[j].e;
t3.s=line[i].e; t3.e=line[j].s;
t4.s=line[i].e; t4.e=line[j].e;
if(t1.s==t1.e){}
else{
if(check(t1)){
isok=true;
break;
}
}
if(t2.s==t2.e){}
else{
if(check(t2)){
isok=true;
break;
}
}
if(t3.s==t3.e){}
else{
if(check(t3)){
isok=true;
break;
}
}
if(t4.s==t4.e){}
else{
if(check(t4)){
isok=true;
break;
}
}
}
}
if(isok) puts("Yes!");
else puts("No!");
}
return 0;
}