- 题解:问题转化很重要,表面上是求是否存在一条直线,然后让所有线段在其投影上有公共部分,其实就是问是否存在一条直线可以穿过所有线段。本质上所有的问题都可以通过遍历点来解决,所以就是遍历每两个点,形成一条直线,然后判每条边是否在两边。
- 代码:
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <vector>
using namespace std;
typedef double ld;
const ld eps = 1e-8;
const int N = 50009;
struct Point {
ld x, y;
Point(ld X = 0, ld Y = 0) { x = X, y = Y; }
Point operator-(Point a) { return Point(x - a.x, y - a.y); }
Point operator+(Point a) { return Point(x + a.x, y + a.y); }
ld operator*(Point a) { return x * a.y - y * a.x; }
ld dis() {
return sqrt(x * x + y * y);
}
} p[N];
int dcmp(ld a, ld b) {
if (fabs(a-b)< eps)return 0;
else if (a > b)return 1;
else return -1;
}
typedef Point Vector;
struct Line {
Point p1, p2;
}L[N];
int cnt[N];
int n, m;
Line l[N];
void solve() {
bool first = 1;
scanf("%d", &n);
if (n == 0) return;
int p_cnt = 0;
for (int i = 1; i <= n; i++) {
ld x1, x2;
scanf("%lf%lf", &x1, &x2);p_cnt++;
p[p_cnt].x = x1, p[p_cnt].y = x2;
scanf("%lf%lf", &x1, &x2);
p_cnt++;
p[p_cnt].x = x1, p[p_cnt].y = x2;
L[i] = {p[p_cnt-1], p[p_cnt]};
}
for (int i = 1; i <= p_cnt; i ++) {
for (int j = i + 1; j <= p_cnt; j ++) {
bool f = 1;
Vector v = p[j] - p[i];
if (dcmp(v.dis(), 0) == 0)continue;
for (int k = 1; k <= n; k ++) {
Vector v1 = L[k].p1 - p[i];
Vector v2 = L[k].p2 - p[i];
int d1 = dcmp(v * v1, 0);
int d2 = dcmp(v * v2, 0);
if (d1 * d2 <= 0) {
continue;
} else {f = 0;break;}
}
if (f) {puts("Yes!");return;}
}
}
if (n == 1 || n == 2) puts("Yes!");
else
puts("No!");
}
signed main() {
//ios::sync_with_stdio(0);
int t = 1;scanf("%d", &t);
while (t--) {
solve();
}
return 0;
}