大致題意:給n條線段,判斷是否存在一條線段,使得所有的線段在它上面的投影是否有公共交點。
大致思路:既然是投影,那很明顯在紙上畫一下就知道,以某條線段作爲x軸建立直角座標系,那就可以輕鬆的
畫出每條線段在x軸上的投影,也就很容易就知道,判斷投影有沒有公共點,其實就是看有沒有一條直線可以穿過所有的線段。
這裏其實稍微跳了一點,但是畫圖就很容易知道我在說什麼。看題目的數據範圍n爲100,所以暴力枚舉任意兩個的端點,判斷這兩個端點的直線是否可以穿過所有的線段。注:枚舉的時候,如果兩個端點的距離小於1e-8,就認爲是同一個點,這次枚舉的端點不算。
同時,通過上面的分析,大膽猜測口嗨一下,如果不考慮線段旋轉的精度誤差,應該可以枚舉旋轉線段,暴力判斷所有線段的左端點的x座標都小於min(所有線段的右端點的x座標)。瞎吹一會,不要在意。
最後,代碼:
#include<iostream>
#include<stdio.h>
#include<math.h>
using namespace std;
int n;
struct line
{
double x1,y1,x2,y2;
}lines[120];
double multiple_cross(double x1,double y1,double x2,double y2)
{
return x1*y2-x2*y1;
}
bool check(line a,line b)
{
double w,z;
w=multiple_cross(a.x1-b.x1,a.y1-b.y1,b.x2-b.x1,b.y2-b.y1);
z=multiple_cross(a.x2-b.x1,a.y2-b.y1,b.x2-b.x1,b.y2-b.y1);
if(w*z<=0)
return true;
return false;
}
bool judge(line ac)
{
if(sqrt((ac.x1-ac.x2)*(ac.x1-ac.x2)+(ac.y1-ac.y2)*(ac.y1-ac.y2))<1e-8)
return false;
bool flag=true;
for(int i=0;i<n;++i)
{
if(!check(lines[i],ac))
flag=false;
}
return flag;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=0;i<n;++i)
{
scanf("%lf %lf %lf %lf",&lines[i].x1,&lines[i].y1,&lines[i].x2,&lines[i].y2);
}
if(n==1||n==2)
{
printf("Yes!\n");
continue;
}
line ac;
bool flag=false;
for(int i=0;i<n;++i)
{
for(int j=i+1;j<n;++j)
{
ac.x1=lines[i].x1,ac.y1=lines[i].y1;
ac.x2=lines[j].x1,ac.y2=lines[j].y1;
if(judge(ac))
{
flag=true;
}
ac.x2=lines[j].x2,ac.y2=lines[j].y2;
if(judge(ac))
{
flag=true;
}
ac.x1=lines[i].x2,ac.y1=lines[i].y2;
if(judge(ac))
{
flag=true;
}
ac.x2=lines[j].x1,ac.y2=lines[j].y1;
if(judge(ac))
{
flag=true;
}
}
}
if(flag)
printf("Yes!\n");
else
printf("No!\n");
}
return 0;
}