嘟嘟嘟
题面就不说了,网上都有。
刚开始理解成了只要有不孤立的线段就算合法,结果就不会了……然而题中要求是所有线段至少有一个交点。
其实想一想就知道,问题转化为了是否存在一条直线和所有线段都有交点。
所以枚举线段的端点构成直线,然后判断直线和线段是否有交点。
具体做法就是对于直线(AB),判断线段(CD)是否在(AB)的两侧,用叉积即可:如果又向面积符号相同,就说明在一侧,即((overrightarrow{AB} imes overrightarrow{AC}) * (overrightarrow{AB} imes overrightarrow{AD}) >= 0)。一定要包含等于(0)的情况,这样就不用特判平行和重合的情况。
别忘了还得特判选取的两点是否重合。
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
#define enter puts("")
#define space putchar(' ')
#define Mem(a, x) memset(a, x, sizeof(a))
#define rg register
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-8;
const int maxn = 505;
inline ll read()
{
ll ans = 0;
char ch = getchar(), last = ' ';
while(!isdigit(ch)) {last = ch; ch = getchar();}
while(isdigit(ch)) {ans = (ans << 1) + (ans << 3) + ch - '0'; ch = getchar();}
if(last == '-') ans = -ans;
return ans;
}
inline void write(ll x)
{
if(x < 0) x = -x, putchar('-');
if(x >= 10) write(x / 10);
putchar(x % 10 + '0');
}
int n;
struct Vec
{
db x, y;
db operator * (const Vec& oth)const
{
return x * oth.y - oth.x * y;
}
};
struct Point
{
db x, y;
Vec operator - (const Point& oth)const
{
return (Vec){x - oth.x, y - oth.y};
}
}a[maxn], b[maxn];
bool judge(Point A, Point B)
{
Vec AB = B - A;
if(fabs(A.x - B.x) < eps && fabs(A.y - B.y) < eps) return 0;
for(int i = 1; i <= n; ++i)
{
Vec AC = a[i] - A, AD = b[i] - A;
if((AB * AC) * (AB * AD) > eps) return 0;
}
return 1;
}
int main()
{
int T = read();
while(T--)
{
n = read();
for(int i = 1; i <= n; ++i)
scanf("%lf%lf%lf%lf", &a[i].x, &a[i].y, &b[i].x, &b[i].y);
bool flg = 0;
if(n < 3) flg = 1;
for(int i = 1; i < n && !flg; ++i)
{
flg = 0;
for(int j = i + 1; j <= n && !flg; ++j)
{
if(judge(a[i], a[j])) flg = 1;
else if(judge(a[i], b[j])) flg = 1;
else if(judge(b[i], a[j])) flg = 1;
else if(judge(b[i], b[j])) flg = 1;
}
}
puts(flg ? "Yes!" : "No!");
}
return 0;
}