• 计算几何 点和线


    题目描述

    有一个nnn个点mmm条边的图画在了平面上,你想知道有多少对边之间对应的线段相交。

    特别地,对于图中的一对边,如果有公共点且只在对应的端点相交,那么我们不认为这对边相交。

    输入描述

    第一行两个整数n,m(1≤n≤1000,1≤m≤2000)n, m(1leq nleq 1000, 1leq mleq 2000)n,m(1n1000,1m2000),表示点数和边数。

    接下来mmm行,每行两个整数(u,v)(u,v)(u,v)表示一条uuu与vvv之间的无向边,保证图中没有重边和自环。

    接下来nnn行,每行两个整数xi,yi(0≤xi,yi≤109)x_i, y_i (0leq x_i, y_ileq 10^9)xi,yi(0xi,yi109)表示图中第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

    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
    ", ans);
    }
    
  • 相关阅读:
    jpype
    Java获取类中的所有方法
    SQL中INNER JOIN、LEFT JOIN、RIGHT JOIN、FULL JOIN区别
    如何用命令将本地项目上传到git
    Java连接Mysql:通过配置文件
    lsof -i:port_number
    yum install lsof
    Git的基本使用方法(受益匪浅)
    [后端]gitlab之gitlab-ci自动部署
    centos7安装redis-4.0.1集群
  • 原文地址:https://www.cnblogs.com/ruthank/p/10321608.html
Copyright © 2020-2023  润新知