1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 用Prim和Kruskal两种算法 求解最小生成树

用Prim和Kruskal两种算法 求解最小生成树

时间:2021-02-25 20:19:39

相关推荐

用Prim和Kruskal两种算法 求解最小生成树

本文通过具体的算法模板题,给出Prim和Kruskal两种求解最小生成树求解过程和代码~

由浅入深,通俗易懂

题目选自洛谷P3366

题目描述

如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出orz

输入格式

第一行包含两个整数N,M,表示该图共有N个结点和M条无向边。

接下来M行每行包含三个整数 Xi​,Yi​,Zi​,表示有一条长度为Zi​的无向边连接结点 Xi​,Yi​。

输出格式

如果该图连通,则输出一个整数表示最小生成树的各边的长度之和。如果该图不连通则输出orz

输入输出样例

输入 1

4 51 2 21 3 21 4 32 3 43 4 3

输出 1

7

说明/提示

数据规模:

对于20%的数据,N≤5,M≤20。

对于40%的数据,N≤50,M≤2500。

对于70%的数据,N≤500,M≤104。

对于 100%的数据:1≤N≤5000,1≤M≤2×10^5,1≤Zi​≤10^4。

前言

两者区别:Prim在稠密图中比Kruskal优,在稀疏图中比Kruskal劣。Prim是以更新过的节点的连边找最小值,Kruskal是直接将边排序。

两者其实都是运用贪心的思路

Prim算法思想:

Prim的思想是将任意节点作为根,再找出与之相邻的所有边(用一遍循环即可),再将新节点更新并以此节点作为根继续搜,维护一个数组:dis,作用为已用点到未用点的最短距离。

具体算法流程图解如下:

优化:

但是!由于该题数据比较大,我们应该做一些优化

例如Prim可以用优先队列(也即 堆)来优化算法

Kruskal算法思想:

Kruskal算法的思想比Prin好理解一些。先把边按照权值进行排序,用贪心的思想优先选取权值较小的边,并依次连接,若出现环则跳过此边继续搜,直到已经使用的边的数量比总点数少一即可。

具体算法流程图解如下:

优化:

但是!由于该题数据比较大,我们应该做一些优化

例如Kruskal可以用并查集优化一下

Prim解题代码:

#include<cstdio>#include<queue>#include<cstring>#include<algorithm>#define R register intusing namespace std;int k,n,m,cnt,sum,ai,bi,ci,head[5005],dis[5005],vis[5005];struct Edge{int v,w,next;}e[400005];void add(int u,int v,int w){e[++k].v=v;e[k].w=w;e[k].next=head[u];head[u]=k;}typedef pair <int,int> pii;priority_queue <pii,vector<pii>,greater<pii> > q;void prim(){dis[1]=0;q.push(make_pair(0,1));while(!q.empty()&&cnt<n){int d=q.top().first,u=q.top().second;q.pop();if(vis[u]) continue;cnt++;sum+=d;vis[u]=1;for(R i=head[u];i!=-1;i=e[i].next)if(e[i].w<dis[e[i].v])dis[e[i].v]=e[i].w,q.push(make_pair(dis[e[i].v],e[i].v));}}int main(){memset(dis,127,sizeof(dis));memset(head,-1,sizeof(head));scanf("%d%d",&n,&m);for(R i=1;i<=m;i++){scanf("%d%d%d",&ai,&bi,&ci);add(ai,bi,ci);add(bi,ai,ci);}prim();if (cnt==n)printf("%d",sum);else printf("orz");}

Kruskal解题代码:

#include<iostream>#include<stdio.h>#include<math.h>#include<algorithm>using namespace std;#define MAX_N 5000+5#define MAX_M 200000+5struct edge{int u,v;int w;}E[MAX_M];int f[MAX_N];int n,m;bool cmp(edge a,edge b){return a.w < b.w;}void init(){for(int i=1;i<=n;i++) f[i] = i;}int find(int x){if(f[x] == x) return x;return f[x] = find(f[x]);}void merge(int x,int y){f[find(x)] = find(y);}int Kruskal(){int ans = 0, cnt = 0;init();sort(E+1,E+1+m,cmp);for(int i = 1;i<=m;i++){if(cnt == n-1) break;if(find(E[i].u) != find(E[i].v)){merge(E[i].u,E[i].v);ans += E[i].w;cnt++;}}if(cnt != n-1) return 0;return ans;}int main(){scanf("%d%d",&n,&m);for(int i = 1;i<=m;i++)scanf("%d%d%d",&E[i].u,&E[i].v,&E[i].w);int ans = Kruskal();if(ans) printf("%d",ans);else printf("orz");return 0;}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。