题目描述
有一个nnn个点mmm条边的图画在了平面上,你想知道有多少对边之间对应的线段相交。
特别地,对于图中的一对边,如果有公共点且只在对应的端点相交,那么我们不认为这对边相交。
输入描述
第一行两个整数n,m(1≤n≤1000,1≤m≤2000)n, m(1\leq n\leq 1000, 1\leq m\leq 2000)n,m(1≤n≤1000,1≤m≤2000),表示点数和边数。
接下来mmm行,每行两个整数(u,v)(u,v)(u,v)表示一条uuu与vvv之间的无向边,保证图中没有重边和自环。
接下来nnn行,每行两个整数xi,yi(0≤xi,yi≤109)x_i, y_i (0\leq x_i, y_i\leq 10^9)xi,yi(0≤xi,yi≤109)表示图中第iii个顶点的坐标,保证所有的坐标两两不同。
输出描述
输出一个整数,表示答案。
样例输入 1
4 6 1 2 1 3 1 4 2 3 2 4 3 4 0 0 0 1 1 1 1 0
样例输出 1
扫描二维码关注公众号,回复:
5068830 查看本文章
1
第一次自己写计算几何,拿来当个板子吧。
虽然题目理解复杂了,也没写对。
对于这类题,写好Point类和Edge类后确实好写很多。
#include <bits/stdc++.h> using namespace std; const int maxn = 2000 + 1005; const double eps = 1e-8; typedef double Ld; struct Point { Ld x, y; Point(Ld xx = 0, Ld yy = 0) : x(xx), y(yy) {} Point operator - (const Point &a) { return Point(x-a.x, y-a.y); } }; struct Edge { int lx, ly, rx, ry; Point lnode, rnode; Edge() {} Edge(Point a, Point b) : lnode(a), rnode(b) {} }; Point Nd[maxn]; int X[maxn], Y[maxn]; Edge e[maxn]; vector<Edge> S, T; bool Eq(Ld x, Ld y) { return fabs(x-y) < eps; } Ld cross(Point a, Point b) { return a.x*b.y - a.y*b.x; } bool coinci(Point a, Point b) { return (Eq(a.x, b.x) && Eq(a.y, b.y)); } bool quick_exclude(Point a1, Point a2, Point b1, Point b2) { if (max(a1.x, a2.x) < min(b1.x, b2.x)) return false; if (max(b1.x, b2.x) < min(a1.x, a2.x)) return false; if (max(a1.y, a2.y) < min(b1.y, b2.y)) return false; if (max(b1.y, b2.y) < min(a1.y, a2.y)) return false; return true; } bool walk_across(Point a1, Point a2, Point b1, Point b2) { if (!quick_exclude(a1, a2, b1, b2)) return false; if (coinci(a1, b1) || coinci(a1, b2) || coinci(a2, b1) || coinci(a2, b2)) return false; if (cross(a1-b1, b2-b1) * cross(a2-b1, b2-b1) > 0) return false; if (cross(b1-a1, a2-a1) * cross(b2-a1, a2-a1) > 0) return false; return true; } bool check(Edge &cat, Edge a, Edge b) { //判断斜率相等 或者 都无斜率 Ld k1, k2; Point Va = a.lnode - a.rnode, Vb = b.lnode - b.rnode; if (Va.x) k1 = Va.y / Va.x; if (Vb.x) k2 = Vb.y / Vb.x; if (Eq(Va.x, 0) + Eq(Vb.x, 0) == 1) return false; if (!Eq(k1, k2)) return false; //有公共点 if (coinci(a.lnode, b.lnode)) cat = Edge(a.rnode, b.rnode); else if (coinci(a.lnode, b.rnode)) cat = Edge(a.rnode, b.lnode); else if (coinci(a.rnode, b.lnode)) cat = Edge(a.lnode, b.rnode); else if (coinci(a.rnode, b.rnode)) cat = Edge(a.lnode, b.lnode); else return false; return true; } int main() { freopen("in.txt", "r", stdin); int n, m; scanf("%d%d", &n, &m); for (int i = 1; i <= m; i++) scanf("%d%d", &X[i], &Y[i]); for (int i = 1; i <= n; i++) scanf("%lf%lf", &(Nd[i].x), &(Nd[i].y)); int ans = 0; for (int i = 1; i <= m; i++) { e[i] = Edge(Nd[X[i]], Nd[Y[i]]); Edge cat; int sz = S.size(); for (int j = 0; j < sz; j++) { if (walk_across(e[i].lnode, e[i].rnode, S[j].lnode, S[j].rnode)) ans++; while (check(cat, e[i], S[j])) { for (int k = 0; k < sz; k++) if (k != j && walk_across(cat.lnode, cat.rnode, S[k].lnode, S[k].rnode)) ans++; S.push_back(cat); } } S.push_back(e[i]); } printf("%d\n", ans); }