『最小生成树』prim & Kruskal

Kruskal和prim都是求最小生成树的方法,两种方法都是按照贪心来做的。但是Kruskal是从边的角度入手,prim则是从点的角度入手。prim运用类似Dijkstra的方法来求,Kruskal运用并查集来求。

在复杂度方面,两种算法各有所长。

在稀疏图中,枚举边的Kruskal效率更高,在稠密图中,枚举点的prim效率更高。

Kruskal算法

按照边权从小到大排序,每次判断当前边两边的点是否连通,如果没有连通,就加入这条边。

连通性我们可以用并查集维护。

复杂度为\(O(m*log_m+m)\)

附上代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<math.h>
#include<queue>
using namespace std;
struct nod{
    int f,t,w;
};
nod edge[200005];
int fa[5005];
int n,m;
inline int cmp(nod a,nod b){
    return a.w<b.w;
}
inline int getfa(int a){
    return fa[a]==a?a:fa[a]=getfa(fa[a]);
}
inline void unio(int a,int b){
    fa[getfa(a)]=getfa(b);
}
int main(){
    std::ios::sync_with_stdio(false);
    for(register int i=0;i<=5000;i++){
        fa[i]=i;
    }
    cin>>n>>m;
    for(register int i=1;i<=m;i++){
        cin>>edge[i].f>>edge[i].t>>edge[i].w;
    }
    sort(edge+1,edge+m+1,cmp);
    int ans=0;
    for(register int i=1;i<=m;i++){
        if(getfa(edge[i].f)!=getfa(edge[i].t)){
            unio(edge[i].f,edge[i].t);
            ans+=edge[i].w;
        }
    }
    cout<<ans<<endl;
    return 0;
}

prim算法

prim算法的核心思想是枚举到当前树距离最近的点,然后加入到当前的树中。每次找到最近的没有在树中的点,然后加入数中,更新最近距离。

复杂度为\(O(n^2)\),当然也可以优化。

附上代码

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
const int maxn=5005;
const int INF=0x3f3f3f3f;
int n,m,cnt=1,ans=0;
int map[maxn][maxn],dis[maxn],fr[maxn];
bool vis[maxn];
inline void prim(){
    vis[1]=1,dis[1]=0,fr[1]=1;
    for(register int i=1;i<=n;i++)dis[i]=map[1][i];
    for(register int i=1;i<=n;i++){
        int mi=INF,v=-1;
        for(register int j=1;j<=n;j++)
            if(!vis[j]&&dis[j]<mi)mi=dis[j],v=j;
        if(v!=-1){
            cnt++;
            vis[v]=1;
            ans+=dis[v];
            for(register int j=1;j<=n;j++){
                if(vis[j])continue;
                if(dis[j]>map[v][j]){
                    dis[j]=map[v][j];
                    fr[j]=v;
                }
            }
        }
    }
}
int main(){
    memset(map,0x3f,sizeof(map));
    scanf("%d%d",&n,&m);
    for(register int i=1,x,y,z;i<=m;i++){
        scanf("%d%d%d",&x,&y,&z);
        map[x][y]=map[y][x]=min(map[x][y],z);
    }
    prim();
    cout<<ans<<endl;
}

原文地址:https://www.cnblogs.com/Fang-Hao/p/9652015.html

时间: 2024-11-08 23:09:45

『最小生成树』prim & Kruskal的相关文章

最小生成树之Prim Kruskal算法(转)

最小生成树 首先,生成树是建立在无向图中的,对于有向图,则没有生成树的概念,所以接下来讨论的图均默认为无向图.对于一个有n个点的图,最少需要n-1条边使得这n个点联通,由这n-1条边组成的子图则称为原图的生成树.一般来说,一个图的生成树并不是唯一的(除非原图本身就是一棵树). 现在考虑带权图G,即图的边带权,则最小生成树就是在G中权值和最小的一颗生成树,显然最小生成树也不是唯一的,但是其权值唯一.有很多应用需要用到最小生成树的概念,比较直观的一个应用就是:有n个村庄,现在要在这些村庄之间修一些路

最小生成树求法 Prim + Kruskal

prim算法的思路 和dijkstra是一样的 每次选取一个最近的点 然后去向新的节点扩张 注意这里的扩张 不再是 以前求最短路时候的到新的节点的最短距离 而是因为要生成一棵树 所以是要连一根最短的连枝 所以关键部分修改一下 dist[u] = min(dist[u], e.cost) --->>e是连接 v 和 u的边 同样地 普同写法O(v^2) 用队列优化后O(E*logV) 1 #include <iostream> 2 #include <stdio.h> 3

最小生成树(prim&amp;kruskal)

最近都是图,为了防止几次记不住,先把自己理解的写下来,有问题继续改.先把算法过程记下来: prime算法:                                           原始的加权连通图——————D被选作起点,选与之相连的权值最小的边————选与D.A相连权值最小的边——————可选的有B(7).E(8).G(11)                   ————————————————————————————————————————————————————————————

数据结构之 图论---最小生成树(prim + kruskal)

图结构练习——最小生成树 Time Limit: 1000MS Memory limit: 65536K 题目描述 有n个城市,其中有些城市之间可以修建公路,修建不同的公路费用是不同的.现在我们想知道,最少花多少钱修公路可以将所有的城市连在一起,使在任意一城市出发,可以到达其他任意的城市. 输入 输入包含多组数据,格式如下. 第一行包括两个整数n m,代表城市个数和可以修建的公路个数.(n<=100) 剩下m行每行3个正整数a b c,代表城市a 和城市b之间可以修建一条公路,代价为c. 输出

poj1861 最小生成树 prim &amp; kruskal

// poj1861 最小生成树 prim & kruskal // // 一个水题,为的只是回味一下模板,日后好有个照应不是 #include <cstdio> #include <algorithm> #include <cstring> #include <vector> #include <iostream> using namespace std; const int MAX_N = 1008; const int INF =

最小生成树(prim算法,Kruskal算法)c++实现

1.生成树的概念 连通图G的一个子图如果是一棵包含G的所有顶点的树,则该子图称为G的生成树. 生成树是连通图的极小连通子图.所谓极小是指:若在树中任意增加一条边,则将出现一个回路:若去掉一条边,将会使之变成非连通图. 生成树各边的权值总和称为生成树的权.权最小的生成树称为最小生成树. 2.最小生成树的性质用哲学的观点来说,每个事物都有自己特有的性质,那么图的最小生成树也是不例外的.按照生成树的定义,n 个顶点的连通网络的生成树有 n 个顶点.n-1 条边. 3.构造最小生成树,要解决以下两个问题

最小生成树之 prim算法和kruskal算法(以 hdu 1863为例)

最小生成树的性质 MST性质:设G = (V,E)是连通带权图,U是V的真子集.如果(u,v)∈E,且u∈U,v∈V-U,且在所有这样的边中, (u,v)的权c[u][v]最小,那么一定存在G的一棵最小生成树,(u,v)为其中一条边. 构造最小生成树,要解决以下两个问题: (1).尽可能选取权值小的边,但不能构成回路(也就是环). (2).选取n-1条恰当的边以连接网的n个顶点. Prim算法的思想: 设G = (V,E)是连通带权图,V = {1,2,-,n}.先任选一点(一般选第一个点),首

最小生成树详解 prim+ kruskal代码模板

最小生成树概念: 一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边. 最小生成树可以用kruskal(克鲁斯卡尔)算法或prim(普里姆)算法求出.最小生成树其实是最小权重生成树的简称. prim: 概念:普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树.意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点,且其所有边的权值之和亦为最小. 实现过程: 图例 说明 不可选 可选 已选(Vn

最小生成树:prim算法和kruskal算法

一个连通图的生成树是图的极小连通子图.它包含图中的所有顶点,并且只含尽可能少的边.若砍去它的一条边,就会使生成树变成非连通图:若给它增加一条边,则会形成一条回路. 最小生成树有如下性质: 1.最小生成树非唯一,可能有多个最小生成树: 2.最小生成树的边的权值之和总唯一,而且是最小的: 3.最小生成树的边数为顶点数减1. 构造最小生成树可以有多种算法.其中多数算法利用了最小生成树的下列一种简称为MST的性质: 假设N=(V,{E})是一个连通网,U是顶点集V的一个非空子集.若(u, v)是一条具有