P3366 【模板】最小生成树(boruvka/sollin)

P3366 【模板】最小生成树

boruvka/sollin

复杂度$O(mlogn)$

简要说明一下过程

引入一个数组$link[i]$表示连通块$i$下一步可更新的最短的边的编号

1.每次枚举所有边,如果边连接的2个点$(u,v)$不属于同连通块,那么更新$link[find(u)],link[find(v)]$(find(u)表示$u$所属的连通块)

2.枚举所有连通块,将$link[i]$两边的连通块合并。

3.如果第2步中有合并操作,则跳到1

注意更新$link[i]$,当比较的两条边权值相同时,要有确定的大小顺序,通常优先取编号小的。

#include<cstdio>
#include<cstring>
#define N 5005
#define M 200005
int n,m,k,ans,fa[N],link[N],U[M],V[M],W[M]; bool vis[M];
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
inline bool fc(int x,int y){return W[x]==W[y]?x<y:W[x]<W[y];}
void boruvka(){
    for(bool ok=1;ok;){
        memset(link,0,sizeof(link)); ok=0;
        for(int i=1;i<=m;++i) if(!vis[i]){
            int r1=find(U[i]),r2=find(V[i]);
            if(r1==r2) continue;
            if(fc(i,link[r1])) link[r1]=i;
            if(fc(i,link[r2])) link[r2]=i;
        }
        for(int i=1;i<=n;++i) if(!vis[link[i]]&&link[i]){
            vis[link[i]]=ok=1; ans+=W[link[i]]; ++k;
            fa[find(U[link[i]])]=find(V[link[i]]);
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i) fa[i]=i;
    for(int i=1;i<=m;++i) scanf("%d%d%d",&U[i],&V[i],&W[i]);
    W[0]=1e9; boruvka();
    k==n-1 ? printf("%d",ans):puts("orz");
    return 0;
}

原文地址:https://www.cnblogs.com/kafuuchino/p/10534127.html

时间: 2024-08-29 13:43:46

P3366 【模板】最小生成树(boruvka/sollin)的相关文章

luoguP3366 [模板] 最小生成树

题目链接:https://www.luogu.org/problemnew/show/P3366 思路: 求最小生成树的模板题,求MST有两种算法--Prim.Kruskal. 两者区别:Prim在稠密图中比Kruskal优,在稀疏图中比Kruskal劣.Prim是以更新过的节点的连边找最小值,Kruskal是直接将边排序. 两者其实都是运用贪心的思路 我使用的Prim算法(邻接表实现),head是表头结点数组,a是表结点数组,len记录未加入生成树的结点到生成树的最小距离,vis用来记录结点是

模板——最小生成树kruskal算法+并查集数据结构

并查集:找祖先并更新,注意路径压缩,不然会时间复杂度巨大导致出错/超时 合并:(我的祖先是的你的祖先的父亲) 找父亲:(初始化祖先是自己的,自己就是祖先) 查询:(我们是不是同一祖先) 路径压缩:(每个点只保存祖先,不保存父亲) 最小生成树kruskal:贪心算法+并查集数据结构,根据边的多少决定时间复杂度,适合于稀疏图 核心思想贪心,找到最小权值的边,判断此边连接的两个顶点是否已连接,若没连接则连接,总权值+=此边权值,已连接就舍弃继续向下寻找: 并查集数据结构程序: #include<ios

模板 最小生成树

堆优化的prim算法(跟dijkstra非常的像) #include<iostream> #include<queue> #include<vector> using namespace std; const int inf=99999999; int n,m; vector<pair<int,int> >g[5005];//第一位是距离,第二位使编号 int book[5005],dis[5005]; priority_queue<pai

【模板】图论

一.生成树 洛谷模板最小生成树[跑的还算快的 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define N 5020 #define M 200008 using namespace std; int n,m,ans; int tot; int fa[N]; struct E{ int x,y,z; }e[M]; bool cmp(E a,E b){ r

洛谷P3366 【模板】最小生成树

P3366 [模板]最小生成树 319通过 791提交 题目提供者HansBug 标签 难度普及- 提交  讨论  题解 最新讨论 里面没有要输出orz的测试点 如果你用Prim写了半天都是W- 题目描述有错 题目描述 如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出orz 输入输出格式 输入格式: 第一行包含两个整数N.M,表示该图共有N个结点和M条无向边.(N<=5000,M<=200000) 接下来M行每行包含三个整数Xi.Yi.Zi,表示有一条长度为Zi的无向边连接结点Xi

【原创】洛谷 LUOGU P3366 【模板】最小生成树

P3366 [模板]最小生成树 题目描述 如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出orz 输入输出格式 输入格式: 第一行包含两个整数N.M,表示该图共有N个结点和M条无向边.(N<=5000,M<=200000) 接下来M行每行包含三个整数Xi.Yi.Zi,表示有一条长度为Zi的无向边连接结点Xi.Yi 输出格式: 输出包含一个数,即最小生成树的各边的长度之和:如果该图不连通则输出orz 输入输出样例 输入样例#1: 4 5 1 2 2 1 3 2 1 4 3 2 3 4

洛谷 P3366 【模板】最小生成树 如题

P3366 [模板]最小生成树 时空限制1s / 128MB 题目描述 如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出orz 输入输出格式 输入格式: 第一行包含两个整数N.M,表示该图共有N个结点和M条无向边.(N<=5000,M<=200000) 接下来M行每行包含三个整数Xi.Yi.Zi,表示有一条长度为Zi的无向边连接结点Xi.Yi 输出格式: 输出包含一个数,即最小生成树的各边的长度之和:如果该图不连通则输出orz 输入输出样例 输入样例#1: 4 5 1 2 2 1

最小生成树模板题-----P3366 【模板】最小生成树

题目描述 如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出orz 输入格式 第一行包含两个整数N.M,表示该图共有N个结点和M条无向边.(N<=5000,M<=200000) 接下来M行每行包含三个整数Xi.Yi.Zi,表示有一条长度为Zi的无向边连接结点Xi.Yi 输出格式 输出包含一个数,即最小生成树的各边的长度之和:如果该图不连通则输出orz 输入输出样例 输入 #1复制 4 5 1 2 2 1 3 2 1 4 3 2 3 4 3 4 3 输出 #1复制 7 说明/提示 时空

洛谷 P3366 【模板】最小生成树

题目描述 如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出orz 输入输出格式 输入格式: 第一行包含两个整数N.M,表示该图共有N个结点和M条无向边.(N<=5000,M<=200000) 接下来M行每行包含三个整数Xi.Yi.Zi,表示有一条长度为Zi的无向边连接结点Xi.Yi 输出格式: 输出包含一个数,即最小生成树的各边的长度之和:如果该图不连通则输出orz 输入输出样例 输入样例#1: 4 5 1 2 2 1 3 2 1 4 3 2 3 4 3 4 3 输出样例#1: 7