2984. 线段
题目链接
2984. 线段
在二维平面内有 \(n\) 条线段,请你编写一个程序,判断是否存在一条直线满足将这 \(n\) 条线段投影到该直线上后,所有的投影线段至少具有一个公共点。
输入格式
第一行包含整数 \(T\),表示共有 \(T\) 组测试数据。
每组数据第一行包含整数 \(n\),表示共有 \(n\) 条线段。
接下来 \(n\) 行,每行包含四个实数 \(x_1,y_1,x_2,y_2\),其中 \((x_1,y_1)\) 和 \((x_2,y_2)\) 是一条线段的两端点坐标。
输出格式
对于每组数据,如果存在满足条件的线段,则输出一行 Yes!
,否则输出一行 No!
。
如果两个浮点数 \(a\) 与 \(b\) 满足 \(|a-b| < 10^{-8}\),则你可以认为这两个数相等。
数据范围
\(1 \le T \le 100\),
\(1 \le n \le 100\),
\(-10^9 \le x_1,y_1,x_2,y_2 \le 10^9\)
输入样例:
3
2
1.0 2.0 3.0 4.0
4.0 5.0 6.0 7.0
3
0.0 0.0 0.0 1.0
0.0 1.0 0.0 2.0
1.0 1.0 2.0 1.0
3
0.0 0.0 0.0 1.0
0.0 2.0 0.0 3.0
1.0 1.0 2.0 1.0
输出样例:
Yes!
Yes!
No!
解题思路
计算几何
问题等价于判断是否存在一条直线能否穿过所有线段,假设存在这样一条直线,则该直线一定可以通过旋转且穿过所有线段的前提下穿过某条线段的某个端点,同理,到达该端点后还可以到达另外一个端点,即这样的直线可以通过已知的端点构造出来,暴力所有这样的直线,然后通过叉积判断是否所有的线段的两个端点都在直线两侧
- 时间复杂度:\(O(n^3)\)
代码
// Problem: 线段
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/description/2987/
// Memory Limit: 64 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const int N=105;
const double eps=1e-8;
typedef pair<double,double> PDD;
int t,n;
PDD a[N],b[N],c[N<<1];
int sign(double x)
{
if(fabs(x)<eps)return 0;
if(x>0)return 1;
return -1;
}
int cmp(double x,double y)
{
if(fabs(x-y)<eps)return 0;
if(x>y)return 1;
return -1;
}
double cross(double x1,double y1,double x2,double y2)
{
return x1*y2-x2*y1;
}
double area(PDD a,PDD b,PDD c)
{
return cross(b.fi-a.fi,b.se-a.se,c.fi-a.fi,c.se-a.se);
}
bool ck()
{
for(int i=1;i<=2*n;i++)
for(int j=i+1;j<=2*n;j++)
{
if(!cmp(c[i].fi,c[j].fi)&&!cmp(c[i].se,c[j].se))continue;
bool f=true;
for(int k=1;k<=n;k++)
if(sign(area(c[i],c[j],a[k]))*sign(area(c[i],c[j],b[k]))>0)
{
f=false;
break;
}
if(f)return true;
}
return false;
}
int main()
{
for(cin>>t;t;t--)
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i].fi>>a[i].se>>b[i].fi>>b[i].se;
c[i]=a[i],c[i+n]=b[i];
}
puts(ck()?"Yes!":"No!");
}
return 0;
}