题意:有N个矩阵,每个矩阵有两个对角线,现在从每个矩阵的两条对角线中选出一条,使得选出的这N条对角线相互之间没有相交。
思路:首先我们可以假设,选对角线1或对角线2,那么就能有选1不能选1'这样的情况出现,我们将这样的情况去建图,那么其实就是一个2-SAT问题,那么剩下的就是判断线段交了,这里推荐快速排斥试验+跨立实验。
注意,平行且重叠也算是相交,不能用交点来直接判断。
#include <iostream> #include <cstdio> #include <cmath> #include <string> #include <cstring> #include <algorithm> #include <limits> #include <vector> #include <stack> #include <queue> #include <set> #include <map> #include <bitset> #include <unordered_map> #include <unordered_set> #define lowbit(x) ( x&(-x) ) #define e 2.718281828459045 #define INF 0x3f3f3f3f #define HalF (l + r)>>1 #define lsn rt<<1 #define rsn rt<<1|1 #define Lson lsn, l, mid #define Rson rsn, mid+1, r #define QL Lson, ql, qr #define QR Rson, ql, qr #define myself rt, l, r #define pii pair<int, int> #define MP(a, b) make_pair(a, b) using namespace std; typedef unsigned long long ull; typedef unsigned int uit; typedef long long ll; const double eps = 1e-8; const double pi = acos(-1.0); int cmp(double x) { if(fabs(x) < eps) return 0; if(x > 0) return 1; else return -1; } inline double sqr(double x) { return x * x; } struct Point { double x, y; Point(double a = 0., double b = 0.):x(a), y(b) {} void Input() { scanf("%lf%lf", &x, &y); } friend Point operator + (const Point &a, const Point &b) { return Point(a.x + b.x, a.y + b.y); } friend Point operator - (const Point &a, const Point &b) { return Point(a.x - b.x, a.y - b.y); } friend bool operator == (const Point &a, const Point &b) { return cmp(a.x - b.x) == 0 && cmp(a.y - b.y) == 0; } friend Point operator * (const Point &a, const double &b) { return Point(a.x * b, a.y * b); } friend Point operator / (const Point &a, const double &b) { return Point(a.x / b, a.y / b); } double norm() { return sqrt(sqr(x) + sqr(y)); } }; double det(const Point &a, const Point &b) //向量叉积 { return a.x * b.y - a.y * b.x; } double dot(const Point &a, const Point &b) //向量点积 { return a.x * b.x + a.y * b.y; } double dist(const Point &a, const Point &b) //两点距离 { return (a - b).norm(); } Point Rotate_Point(const Point &p, double A) //op绕原点逆时针旋转A(弧度) { double tx = p.x, ty = p.y; return Point(tx * cos(A) - ty * sin(A), tx * sin(A) + ty * cos(A)); } struct Line { Point a, b; Line(Point x = Point(), Point y = Point()):a(x), b(y) {} }; Line Point_make_line(const Point a, const Point b) { return Line(a, b); } double dis_Point_Segement(const Point p, const Point s, const Point t) //p到线段st的距离 { if(cmp(dot(p - s, t - s)) < 0) return (p - s).norm(); if(cmp(dot(p - t, s - t)) < 0) return (p - t).norm(); return fabs(det(s - p, t - p) / dist(s, t)); } bool PointOnSegement(Point p, Point s, Point t) //p点是否在线段st上(包括端点) { return cmp(det(p - s, t - s)) == 0 && cmp(dot(p - s, p - t)) <= 0; } bool parallel(Line a, Line b) //线段平行 { return !cmp(det(a.a - a.b, b.a - b.b)); } bool line_make_point(Line a, Line b, Point &res) //线段相交 { if(parallel(a, b)) return false; double s1 = det(a.a - b.a, b.b - b.a); double s2 = det(a.b - b.a, b.b - b.a); res = (a.b * s1 - a.a * s2) / (s1 - s2); return true; } const int maxN = 2e3 + 7; int N, n; Point a[4]; bool cmp_P(Point e1, Point e2) { return e1.x == e2.x ? e1.y < e2.y : e1.x < e2.x; } Line xl[maxN]; int head[maxN], cnt; struct Eddge { int nex, to; Eddge(int a=-1, int b=0):nex(a), to(b) {} } edge[maxN * maxN]; inline void addEddge(int u, int v) { edge[cnt] = Eddge(head[u], v); head[u] = cnt ++; } int dfn[maxN], low[maxN], tot, Stap[maxN], Stop, Belong[maxN], Bcnt; bool instack[maxN]; void Tarjan(int u) { dfn[u] = low[u] = ++ tot; Stap[++Stop] = u; instack[u] = true; for(int i = head[u], v; ~i; i = edge[i].nex) { v = edge[i].to; if(!dfn[v]) { Tarjan(v); low[u] = min(low[u], low[v]); } else if(instack[v]) low[u] = min(low[u], dfn[v]); } if(dfn[u] == low[u]) { int v; Bcnt ++; do { v = Stap[Stop --]; instack[v] = false; Belong[v] = Bcnt; } while(u ^ v); } } inline void init() { cnt = 0; tot = Stop = Bcnt = 0; for(int i = 0; i <= n; i ++) { dfn[i] = 0; instack[i] = false; head[i] = -1; } } double direction(Point p1, Point p2, Point p) { return (p1.x - p.x) * (p2.y - p.y) - ( p2.x - p.x) * (p1.y - p.y); } int on_segment(Point p1, Point p2 , Point p ) { double max=p1.x > p2.x ? p1.x : p2.x; double min =p1.x < p2.x ? p1.x : p2.x; if( p.x >=min && p.x <=max ) return 1; else return 0; } int segments_intersert(Point p1, Point p2, Point p3, Point p4 ) { double d1,d2,d3,d4; d1 = direction ( p1, p2, p3 ); d2 = direction ( p1, p2, p4 ); d3 = direction ( p3, p4, p1 ); d4 = direction ( p3, p4, p2 ); if( d1 * d2 < 0 && d3 * d4 < 0 ) return 1; else if( d1 == 0 && on_segment( p1, p2, p3 ) ) return 1; else if( d2==0 && on_segment( p1, p2, p4 ) ) return 1; else if( d3==0 && on_segment( p3, p4, p1 ) ) return 1; else if( d4==0 && on_segment( p3, p4, p2 ) ) return 1; return 0; } int segments_intersert(Line p, Line q) { return segments_intersert(p.a, p.b, q.a, q.b); } int main() { while(scanf("%d", &N) && N) { n = 0; for(int i = 1; i <= N; i ++) { for(int j = 0; j < 4; j ++) a[j].Input(); sort(a, a + 4, cmp_P); xl[n ++] = Line(a[0], a[3]); xl[n ++] = Line(a[1], a[2]); } init(); for(int i = 0; i < n; i ++) { for(int j = (i & 1 ? i + 1 : i + 2); j < n; j ++) { if(segments_intersert(xl[i], xl[j])) { addEddge(i, j ^ 1); addEddge(j, i ^ 1); } } } for(int i = 0; i < n; i ++) if(!dfn[i]) Tarjan(i); bool ok = true; for(int i = 0; ok && i < n; i += 2) { if(Belong[i] == Belong[i | 1]) ok = false; } printf(ok ? "YES " : "NO "); } return 0; }