題目鏈接:點擊這裏
題意:給出n個線段,能否找到一個直線使得所有線段在直線上的投影至少有一個交點。
可以轉化爲找到與n個線段都相交的直線,那麼所有的直線就是與這條垂直的直線。所以直接枚舉任意兩個直線的任意兩個端點。
trick:當兩個點的距離小於精度時認爲他們是同一個點直接跳過。
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
#define maxn 105
const double eps = 1e-8;
const double INF = 1e20;
const double pi = acos (-1.0);
int dcmp (double x) {
if (fabs (x) < eps) return 0;
return (x < 0 ? -1 : 1);
}
inline double sqr (double x) {return x*x;}
//*************點
struct Point {
double x, y;
Point (double _x = 0, double _y = 0):x(_x), y(_y) {}
void input () {scanf ("%lf%lf", &x, &y);}
void output () {printf ("%.2f %.2f\n", x, y);}
bool operator == (const Point &b) const {
return (dcmp (x-b.x) == 0 && dcmp (y-b.y) == 0);
}
bool operator < (const Point &b) const {
return (dcmp (x-b.x) == 0 ? dcmp (y-b.y) < 0 : x < b.x);
}
Point operator + (const Point &b) const {
return Point (x+b.x, y+b.y);
}
Point operator - (const Point &b) const {
return Point (x-b.x, y-b.y);
}
Point operator * (double a) {
return Point (x*a, y*a);
}
Point operator / (double a) {
return Point (x/a, y/a);
}
double len2 () {//返回長度的平方
return sqr (x) + sqr (y);
}
double len () {//返回長度
return sqrt (len2 ());
}
Point change_len (double r) {//轉化爲長度爲r的向量
double l = len ();
if (dcmp (l) == 0) return *this;//零向量返回自身
r /= l;
return Point (x*r, y*r);
}
Point rotate_left () {//順時針旋轉90度
return Point (-y, x);
}
Point rotate_right () {//逆時針旋轉90度
return Point (y, -x);
}
Point rotate (Point p, double ang) {//繞點p逆時針旋轉ang
Point v = (*this)-p;
double c = cos (ang), s = sin (ang);
return Point (p.x + v.x*c - v.y*s, p.y + v.x*s + v.y*c);
}
Point normal () {//單位法向量
double l = len ();
return Point (-y/l, x/l);
}
};
double cross (Point a, Point b) {//叉積
return a.x*b.y-a.y*b.x;
}
double dot (Point a, Point b) {//點積
return a.x*b.x + a.y*b.y;
}
double dis (Point a, Point b) {//兩個點的距離
Point p = b-a; return p.len ();
}
double degree_rad (double ang) {//角度轉化爲弧度
return ang/180*pi;
}
double rad_degree (double rad) {//弧度轉化爲角度
return rad/pi*180;
}
double rad (Point a, Point b) {//兩個向量的夾角
return fabs (atan2 (fabs (cross (a, b)), dot (a, b)) );
}
bool parallel (Point a, Point b) {//向量平行
double p = rad (a, b);
return dcmp (p) == 0 || dcmp (p-pi) == 0;
}
//************直線 線段
struct Line {
Point s, e;//直線的兩個點
double k;//極角 範圍[-pi,pi]
Line () {}
Line (Point _s, Point _e) {
s = _s, e = _e;
k = atan2 (e.y - s.y,e.x - s.x);
}
//ax+by+c = 0
Line (double a, double b, double c) {
if (dcmp (a) == 0) {
s = Point (0, -c/b);
e = Point (1, -c/b);
}
else if (dcmp (b) == 0) {
s = Point (-c/a, 0);
e = Point (-c/a, 1);
}
else {
s = Point (0, -c/b);
e = Point (1, (-c-a)/b);
}
get_angle ();
}
//一個點和傾斜角確定直線
Line (Point p, double ang) {
k = ang;
s = p;
if (dcmp (ang-pi/2) == 0) {
e = s + Point (0, 1);
}
else
e = s + Point (1, tan (ang));
}
void input () {
s.input ();
e.input ();
}
void output () {
printf ("%.2f,%.2f %.2f,%.2f\n", s.x, s.y, e.x, e.y);
}
void adjust () {
if (e < s) swap (e, s);
}
double length () {//求線段長度
return dis (s, e);
}
void get_angle () {
k = atan2 (e.y - s.y,e.x - s.x);
}
double angle () {//直線的傾斜角
if (dcmp (k) < 0) k += pi;
if (dcmp (k-pi) == 0) k -= pi;
return k;
}
Point operator &(const Line &b)const {//直線的交點(保證存在)
Point res = s;
double t = (cross (s - b.s, b.s - b.e))/cross (s - e, b.s - b.e);
res.x += (e.x - s.x)*t;
res.y += (e.y - s.y)*t;
return res;
}
};
int relation (Point p, Line l) {//點和直線的關係
//1:在左側 2:在右側 3:在直線上
int c = dcmp (cross (p-l.s, l.e-l.s));
if (c < 0) return 1;
else if (c > 0) return 2;
else return 3;
}
bool point_on_halfline (Point p, Line l) {//判斷點在射線上
int id = relation (p, l);
if (id != 3) return 0;
return dcmp (dot (p-l.s, l.e-l.s)) >= 0;
}
bool point_on_seg (Point p, Line l) {//判斷點在線段上
return dcmp (cross (p-l.s, l.e-l.s)) == 0 &&
dcmp (dot (p-l.s, p-l.e) <= 0);
//如果忽略端點交點改成小於號就好了
}
bool parallel (Line a, Line b) {//直線平行
return parallel (a.e-a.s, b.e-b.s);
}
int seg_cross_seg (Line a, Line v) {//線段相交判斷
//2:規範相交 1:不規範相交 0:不相交
int d1 = dcmp (cross (a.e-a.s, v.s-a.s));
int d2 = dcmp (cross (a.e-a.s, v.e-a.s));
int d3 = dcmp (cross (v.e-v.s, a.s-v.s));
int d4 = dcmp (cross (v.e-v.s, a.e-v.s));
if ((d1^d2) == -2 && (d3^d4) == -2) return 2;
return (d1 == 0 && dcmp (dot (v.s-a.s, v.s-a.e)) <= 0) ||
(d2 == 0 && dcmp (dot (v.e-a.s, v.e-a.e)) <= 0) ||
(d3 == 0 && dcmp (dot (a.s-v.s, a.s-v.e)) <= 0) ||
(d4 == 0 && dcmp (dot (a.e-v.s, a.e-v.e)) <= 0);
}
int line_cross_seg (Line a, Line v) {//直線和線段相交判斷 a直線v線段
//2:規範相交 1:非規範相交 0:不相交
int d1 = dcmp (cross (a.e-a.s, v.s-a.s));
int d2 = dcmp (cross (a.e-a.s, v.e-a.s));
if ((d1^d2) == -2) return 2;
return (d1 == 0 || d2 == 0);
}
Line l[maxn];
int n;
bool ok (int i, int j, Point a, Point b) {
if (dis (a, b) <= eps) return 0;
Line tmp = Line (a, b);
for (int k = 1; k <= n; k++) if (k != i && k != j) {
if (line_cross_seg (tmp, l[k]) == 0) return 0;
}
return 1;
}
int main () {
int t;
cin >> t;
while (t--) {
cin >> n;
for (int i = 1; i <= n; i++) l[i].input ();
if (n == 1 || n == 2) {
printf ("Yes!\n");
continue;
}
for (int i = 1; i <= n; i++) {
for (int j = i+1; j <= n; j++) {
if (ok (i, j, l[i].s, l[j].s) || ok (i, j, l[i].s, l[j].e) ||
ok (i, j, l[i].e, l[j].e) || ok (i, j, l[i].e, l[j].s)) {
printf ("Yes!\n");
goto out;
}
}
}
printf ("No!\n");
out: ;
}
return 0;
}