• 最小生成树(Kruskal)(并查集)


    最小生成树

    时间限制: 1 Sec  内存限制: 64 MB
    提交: 11  解决: 2
    [提交][状态][讨论版]

    题目描述

    某个宇宙帝国有N个星球,由于宇宙的空间是三维的,因此每个星球的位置可以用三维坐标(X,Y,Z)来表示。任意两个不同的星球i和j都有一条边相连,边的距离是这样计算的:dis[i,j]=min(|Xi-Xj|,|Yi-Yj|,|Zi-Zj|),其中| | 符号表示取绝对值。现在让你来挑N-1条边,让这N个星球连通成一个最小生成树,输出构成最小生成树的N-1条边的长度总和。

    输入

    第1行,一个整数N(1≤N≤100000)。

    接下来有N行,每行三个整数X,Y,Z,表示一个星球的坐标,-1000000000≤X,Y,Z≤1000000000。没有两个星球的位置完全重叠。

    输出

    1行,构成最小生成树的N-1条边的长度总和。

    样例输入

    5
    11 -15 -15
    14  -5 -15
    -1 -1 -5
    10 -4 -1
    19 -4 19
    

    样例输出

    4
    【分析】又一道最小生成树,还是Kruskal算法,本以为能很快写出来,但一开始的建边就把我难住了,注意N≤100000,如果用二重循环建边指定超时。
    所以我们可以将x,y,z分别排序,然后用结构体放进优先队列,再Kruskal就行了。下面是AC代码。
    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <algorithm>
    #include <climits>
    #include <cstring>
    #include <string>
    #include <set>
    #include <map>
    #include <queue>
    #include <stack>
    #include <vector>
    #include <list>
    #include<functional>
    #define mod 1000000007
    #define inf 0x3f3f3f3f
    #define pi acos(-1.0)
    using namespace std;
    typedef long long ll;
    const int N=100005;
    int n,m,k,cnt=-1;
    int d[4][2]= {0,1,1,0,0,-1,-1,0};
    int parent[N+60];
    bool vis[N];
    
    struct man {
        int u,v,w;
        bool operator<(const man&a)const{
        return w>a.w;//最小值优先
        }
    } edg[N];//结构体存节点与节点之间的权值,x,y,z各存一份
    priority_queue<man>q;//优先队列
    struct mann
    {
        int x,y,z,id;
    }mp[N];
    bool cmp1(mann g,mann h) {return g.x<h.x;}
    bool cmp2(mann g,mann h) {return g.y<h.y;}
    bool cmp3(mann g,mann h) {return g.z<h.z;}//分别对x,y,z从小到大排序
    void init() {
        for(int i=0; i<=n; i++)parent[i]=i;
    }//初始化
    int Find(int x) {
        if(parent[x] != x) parent[x] = Find(parent[x]);
        return parent[x];
    }//查找并返回节点x所属集合的根节点
    void Union(int x,int y) {
        x = Find(x);
        y = Find(y);
        if(x == y) return;
        parent[y] = x;
    }//将两个不同集合的元素进行合并
    void Build()//将空间图转化为树,分别将两点间的x,y,z方向上的距离存到优先队列,
    {
        sort(mp,mp+n,cmp1);
        for(int i=1;i<n;i++){
            man s;
            s.u=mp[i-1].id;s.v=mp[i].id;s.w=abs(mp[i-1].x-mp[i].x);
            q.push(s);
        }//从小到大排序,相邻两个数差距最小
        sort(mp,mp+n,cmp2);
        for(int i=1;i<n;i++){
            man s;
            s.u=mp[i-1].id;s.v=mp[i].id;s.w=abs(mp[i-1].y-mp[i].y);
            q.push(s);
        }
        sort(mp,mp+n,cmp3);
        for(int i=1;i<n;i++){
            man s;
            s.u=mp[i-1].id;s.v=mp[i].id;s.w=abs(mp[i-1].z-mp[i].z);
            q.push(s);
        }
    }
    void Kruskal() {
       ll sumweight=0;//生成树的总权值
        int num=0;//已经选用边的数目
        int u,v;//顶点
        init();
        while(1) {
                man t=q.top();q.pop();
            u=t.u;
            v=t.v;
            if(Find(u)!=Find(v)) {
                sumweight+=t.w;
                num++;
                Union(u,v);
            }
            if(num>=n-1) break;//边已经全部建好
        }
        printf("%lld
    ",sumweight);
    }
    int main() {
        memset(vis,false,sizeof(vis));
        int u,v,w;
        cin>>n;
        for(int i=0; i<n; i++){
             cin>>mp[i].x>>mp[i].y>>mp[i].z;mp[i].id=i;
        }
        Build();
        Kruskal();
        return 0;
    }
    View Code
    
    
    

  • 相关阅读:
    Codeforces Round #273 (Div. 2) B . Random Teams 贪心
    Codeforces Round #250 (Div. 2)B. The Child and Set 暴力
    Codeforces Round #250 (Div. 1) B. The Child and Zoo 并查集
    微信小程序从零开始开发步骤(二)创建小程序页面
    微信小程序从零开始开发步骤(二)创建小程序页面
    微信小程序从零开始开发步骤(一)搭建开发环境
    微信小程序从零开始开发步骤(一)搭建开发环境
    七个帮助你处理Web页面层布局的jQuery插件
    前端切图:CSS实现隐藏滚动条同时又可以滚动
    前端切图:CSS实现隐藏滚动条同时又可以滚动
  • 原文地址:https://www.cnblogs.com/jianrenfang/p/5726120.html
Copyright © 2020-2023  润新知