• 【CEOI 2020】 Roads(道路)


    Description

    政府想修建一个新的公路网,共 2*N 个城市,目前已经完成 N 条公路,每条公路都是用直线连接两个城市,且没有两条路有公共点包括没有公共端点。

    你的任务是再修建 N-1 条路,且需要满足以下三个条件:

    1. 每一条路都必须是用一条直线连接两个城市。

    2. 如果两条路(包括新路与旧路、新路与新路之间)有一个公共点,则该点必须是道路的端点。

    3. 新路和旧路共同组成的公路网能连接所有城市,即每对城市都有一条由连接两个城市的路段组成的道路。

    Solution

    首先为了避免斜率正无穷这种极端情况的出现,可以将点进行一个旋转。 ( x , y ) (x,y) (x,y) 逆时针转 α \alpha α 角后的坐标是 ( x cos ⁡ α − y sin ⁡ α , x sin ⁡ α + y cos ⁡ α ) (x\cos\alpha-y\sin\alpha,x\sin\alpha+y\cos\alpha) (xcosαysinα,xsinα+ycosα)

    计算几何题中出现线段需要统计一些结果的,一般使用扫描线来完成。

    假设扫描线从左往右扫。扫描过程中,扫描线会不断被给出的线段分割成若干个区域。当扫描线碰到某条线段的左端点时,说明此时又新增了一个区域。那么我们找出此前该区域内 x x x 坐标最大的点,与当前点连边即可。注意更新各区域的 x x x 坐标最大的点。

    当扫到线段的右端点时,就将两个区域合并,同时更新一下最大的 x x x 坐标。

    具体过程可以用 set \text{set} set 来实现。

    Code

    #include<set>
    #include<cmath>
    #include<cstdio>
    #include<algorithm>
    #define N 100050
    #define inf 10000000000
    #define ldb long double
    using namespace std;
    int n;
    ldb nowx;
    ldb Pi=acos(-1.0),alpha=Pi*(1.0*139/180),cosal=cos(alpha),sinal=sin(alpha);
    struct po
    {
        int rlx,rly;
        ldb x,y;
        void calc()
        {
            x=cosal*rlx-sinal*rly;
            y=cosal*rly+sinal*rlx;
        }
    }a[N<<1];
    struct px
    {
        int id,tp;
        ldb x;
    }c[N<<1];
    struct line
    {
        int st,ed;mutable int pre;
        ldb k,b;
        void calc()
        {
            k=(a[st].y-a[ed].y)/(a[st].x-a[ed].x);
            b=a[st].y-k*a[st].x;
        }
        bool operator <(const line x) const {return k*nowx+b<x.k*nowx+x.b;};
    }now;
    set<line> S;
    set<line>::iterator it;
    bool cmp(px x,px y) {return x.x<y.x;}
    int main()
    {
        freopen("network.in","r",stdin);
        freopen("network.out","w",stdout);
        scanf("%d",&n);
        for (int i=1;i<=2*n;i+=2)
        {
            scanf("%d%d",&a[i].rlx,&a[i].rly);a[i].calc();
            scanf("%d%d",&a[i+1].rlx,&a[i+1].rly);a[i+1].calc();
            if (a[i].x>a[i+1].x) swap(a[i],a[i+1]);
            c[i].x=a[i].x;c[i].id=i;c[i].tp=1;
            c[i+1].x=a[i+1].x;c[i+1].id=i+1;c[i+1].tp=0;        
        }
        sort(c+1,c+2*n+1,cmp);
        now.st=-2;now.ed=0;now.pre=0;now.k=0;now.b=-inf;S.insert(now);
        now.st=-1;now.ed=0;now.pre=0;now.k=0;now.b=inf;S.insert(now);
        for (int i=1;i<=2*n;++i)
        {
            nowx=c[i].x;
            if (c[i].tp)
            {
                now.pre=now.st=c[i].id;now.ed=c[i].id+1;
                now.calc();
                it=S.insert(now).first;--it;
                if (it->pre) printf("%d %d %d %d\n",a[it->pre].rlx,a[it->pre].rly,a[now.st].rlx,a[now.st].rly);
                it->pre=now.st;
            }
            else
            {
                now.st=c[i].id-1;now.ed=c[i].id;
                now.calc();
                it=S.find(now);--it;
                it->pre=now.ed;
                S.erase(now);
            }
        }
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
  • 相关阅读:
    容器的通俗讲解
    【目标检测】42、RepVGG | 使用结构重参数化来实现精度和速度平衡的主干网络
    前端基础之CSS
    浮动元素导致被遮住元素单击事件不响应
    口袋参谋:如何对宝贝关键词进行词根分析?用它就对了!
    LeetCode高频题:一棵树的第i个节点的权重ai定义为:从根节到该节点的路径上,红色节点和蓝色节点的数量之差,求所有节点的权值之和
    (附源码)springboot码头作业管理系统 毕业设计 341654
    第2章 变量和简单数据类型
    极智AI | 有趣的羊驼系列大模型
    鸿蒙应用开发-第二章-JS逻辑分支
  • 原文地址:https://blog.csdn.net/LZX_lzx/article/details/125610070