zoukankan      html  css  js  c++  java
  • 题解 【[ARC076B] Built?】

    【题目描述】

    平面上有 (N) 个城市。第 (i) 个城市的坐标为 ((x_i,y_i)) 。同一个坐标上可能有多个城市。在坐标为 ((a,b)) 的城市和坐标为 ((c,d)) 的城市间建造一条道路需要 (min(|a-c|,|b-d|)) 円。只能在城市与城市间建造道路。

    要使任意两个城市之间有直接或间接道路相连,最少需要多少円?

    【输入格式】

    输入按以下形式:

    [N ]

    [x_1 space y_1 ]

    [x_2 space y_2 ]

    [: ]

    [x_N space y_N ]

    【输出格式】

    请输出使任意两城市间有直接或间接道路连接所需最少钱数。

    【样例输入输出】

    【输入 #1】
    3
    1 5
    3 9
    7 8
    
    【输出 #1】
    3
    
    【输入 #2】
    6
    8 3
    4 9
    12 19
    18 1
    13 5
    7 6
    
    【输出 #2】
    8
    

    【数据规模与约定】

    • (2 leq N leq 10^5)
    • (0 leq x_i,y_i leq 10^9)
    • 输入全为整数
    【样例 (1) 解释】

    在城市 (1) 与城市 (2) 间建造一条道路,在城市 (2) 与城市 (3) 间建造一条道路,花费 (2+1=3) 円。


    感谢 ( ext{zqy}) 大佬的思路


    这题是一个巧妙的图论。

    先讲讲我最开始的暴力思路,对于点 (i) 和点 (j),我们在两点之间建一条长度为 (min(|x_i-x_j|,|y_i-y_j|)) 的边。

    一共有 (n^2) 条边,用 Prim 求最小生成树,所以空间复杂度是 (O(n^2)),时间复杂度是 (O(n^2)),对于本题 (n leq 10^5) 的数据来说,卡卡常就过去了 是不可能过的。


    正解思路是,对于点 (i) 和点 (j),我们构造两条边,分别是 (|x_i-x_j|)(|y_i-y_j|)

    对于点 (i)(j)(k),如果存在 (x_i<x_j<x_k),因为 ((x_j-x_i)+(x_k-x_j)=x_k-x_i),所以 (i,k) 之间的代价为 (x_k-x_i) 的边不会出现在最小生成树中。

    因此,我们只要将横纵坐标排个序,然后在相邻两个数之间建边,用 Kruskal 跑最小生成树就好了。

    代码如下:

    #include<bits/stdc++.h>
    #define rint register long long
    #define int long long
    using namespace std;
    inline int read(){
        int s=0,f=1;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=0;c=getchar();}
        while(c>='0'&&c<='9')s=(s<<1)+(s<<3)+c-48,c=getchar();
        return f?s:-s;
    }
    struct hhd{
        int x,id,type;
        friend bool operator < (hhd a,hhd b){
            return a.x<b.x;
        }
    }a[100010],b[100010],c[200010];
    int n,m,num,ans,cnt,fa[100010];
    int get_fa(int x){
        return x==fa[x]?x:fa[x]=get_fa(fa[x]);
    }
    void add_a(int p){
        c[++num].x=a[p].x-a[p-1].x;
        c[num].id=p-1; c[num].type=1;
    }
    void add_b(int p){
        c[++num].x=b[p].x-b[p-1].x;
        c[num].id=p-1; c[num].type=2;
    }
    void merge_a(int p){
        int id=c[p].id;
        int fa_x=get_fa(a[id].id),fa_y=get_fa(a[id+1].id);
        if(fa_x==fa_y) return;
        fa[fa_x]=fa_y; ans+=c[p].x;
        ++cnt;
    }
    void merge_b(int p){
        int id=c[p].id;
        int fa_x=get_fa(b[id].id),fa_y=get_fa(b[id+1].id);
        if(fa_x==fa_y) return;
        fa[fa_x]=fa_y; ans+=c[p].x;
        ++cnt;
    }
    signed main(){
        n=read();
        for(rint i=1;i<=n;++i){
            a[i].x=read(); b[i].x=read();
            a[i].id=b[i].id=i;
        }
        sort(a+1,a+n+1);
        sort(b+1,b+n+1);
        for(rint i=2;i<=n;++i) add_a(i),add_b(i);
        sort(c+1,c+num+1);
        for(rint i=1;i<=n;++i) fa[i]=i;
        for(rint i=1;i<=num;++i){
            if(c[i].type==1) merge_a(i);
            else merge_b(i);
            if(cnt==n-1)break;
        }
        printf("%lld
    ",ans);
        return 0;
    }
    

    码风很丑,见谅QVJIZ6DSFAY9Y0PP@Q_2_8R.gif

  • 相关阅读:
    十的次方——挖掘并非显而易见的观点与想法
    6-3-5式脑力接龙
    三个臭皮匠,顶上一个诸葛亮——在Google Ideathon上Design Thinking分享
    上瘾:如何打造习惯养成中的产品(投资篇)
    上瘾:如何打造习惯养成中的产品(奖励篇)
    上瘾:如何打造习惯养成中的产品(行动篇)
    上瘾:如何打造习惯养成中的产品(触发器篇)
    上瘾:如何打造习惯养成中的产品
    告别2013拥抱2014
    Design Thinking Workshop @ Agile Tour 2013 Shanghai
  • 原文地址:https://www.cnblogs.com/LCGUO/p/12661386.html
Copyright © 2011-2022 走看看