最小生成树-Kruskal算法
来源:互联网 发布:天猫淘宝 编辑:程序博客网 时间:2024/06/17 01:00
Kruskal算法
最小生成树是典型的贪心法求解的问题,假如有N个节点,则最小生成树会有N-1条边,要每条边权值之和最小,只需要每次选出当前权值最小的边,如果当前边会形成环路,则这条边是无效的也就是加入进去会是冗余的,因为这条边新连通的是两个已经被别的边连通了的节点,如果不会形成环路,就加入这条边,这样就能保证最终的权值之和最小。
具体写法:
判环路一般借助并查集来实现。
而每次提取出权值最小的边,我们可以用结构体来存放边,然后事先通过排序将所有边按照权值由小到大进行排序,然后我们就可以在O(1)的时间内找到当前权值最小的边,当然也可以借助优先队列。
先定义存放边的结构体,同时重载了<运算符和定义了一个存放全部边的数组。
struct edge{ int node1; int node2; int value; bool operator < (edge x){ return value<x.value; }}Array[MaxEdgeNum];
进行排序,直接调用库函数。
sort(Array,Array+N);利用并查集来判断是否会形成环路,这里假设存放Array数组N个元素的父亲节点或者说标志节点的数组为par[N],Find函数用于寻找边的两个端节点所属集合的根节点或者说标志节点,join函数完成这两个节点所属的两个集合的合并和判断是否会形成环路,如果在合并之前两个节点已经同属于一个集合,这时如果再将连接这两个节点的边放入生成树的集合,则会形成回路,举个例子,某个图只有a,b,c三个节点并且相互连通,我们先进行join(a,b),join(b,c)操作连通a,b和b,c,这时已经有一条路径连通三个节点了,如果这时在进行join(a,c)操作连通a,c的话就会形成环路,这里设定如果会产生环路的话返回true。
void init(){ mem(par); for(int i=1;i<=N;i++){ par[i]=i; }}int FindPar(int x){ int a=x,b; while(a!=par[a]) a=par[a]; while(x!=par[x]){ b=par[x]; par[x]=a; x=b; } return a;}bool join(int a,int b){ int x=FindPar(a); int y=FindPar(b); if(x!=y){ par[x]=y; return true; } return false;}
挑选最小生成树的N-1条边,如果找不出足够的N-1条边,说明不存在生成树,图不连通,这里返回 -1代表无解。
long long kruskal(){ int MSTnum=0,ans=0; init(); sort(Array,Array+EdgeNum); for(int i=0;i<EdgeNum;i++){ if(join(Array[i].node1,Array[i].node2)){ MSTnum++; ans+=Array[i].value; if(MSTnum==N-1) break; } } if(MSTnum==N-1) return ans; else return -1;}
如果存在有不存在生成树的情况只需要检查一下选出的边的数量,如果最终这个变量小于N-1,则图不连通,无解,并查集中也可以判断一下所有节点在最终是否都并入了一个集合,但这显然不如前一种方法。
完整代码示例:(题目:hdu-1863)
#include<iostream>#include<cstring>#include<algorithm>using namespace std;#define mem(a) memset(a,0,sizeof(a))#define MaxN 1005#define MaxEdgeNum 2000int par[MaxN],N,EdgeNum;void init(){ mem(par); for(int i=1;i<=N;i++){ par[i]=i; }}int FindPar(int x){ int a=x,b; while(a!=par[a]) a=par[a]; while(x!=par[x]){ b=par[x]; par[x]=a; x=b; } return a;}bool join(int a,int b){ int x=FindPar(a); int y=FindPar(b); if(x!=y){ par[x]=y; return true; } return false;}struct edge{ int node1; int node2; int value; bool operator < (edge x){ return value<x.value; }}Array[MaxEdgeNum];long long kruskal(){ int MSTnum=0,ans=0; init(); sort(Array,Array+EdgeNum); for(int i=0;i<EdgeNum;i++){ if(join(Array[i].node1,Array[i].node2)){ MSTnum++; ans+=Array[i].value; if(MSTnum==N-1) break; } } if(MSTnum==N-1) return ans; else return -1;}int main(){ while(cin>>EdgeNum>>N&&EdgeNum){ for(int i=0;i<EdgeNum;i++){ cin>>Array[i].node1>>Array[i].node2>>Array[i].value; } int ans=kruskal(); if(ans==-1){ cout<<'?'<<endl; } else{ cout<<ans<<endl; } }}
阅读全文
0 0
- Kruskal 最小生成树算法
- 最小生成树Kruskal算法
- 最小生成树----Kruskal算法
- 最小生成树kruskal算法
- 最小生成树 - Kruskal算法
- 最小生成树---Kruskal算法
- 最小生成树(kruskal算法)
- 最小生成树,kruskal算法
- 最小生成树--kruskal算法
- 最小生成树---kruskal算法
- 最小生成树--Kruskal算法
- 最小生成树 : Kruskal 算法
- 最小生成树-Kruskal算法
- 最小生成树 Kruskal算法
- 最小生成树kruskal算法
- 最小生成树kruskal算法
- 【Kruskal】算法 最小生成树
- 最小生成树kruskal算法
- 苏宁面试记录
- 异步过滤器-19
- 今日总结
- Mybatis错误:Result Maps collection already contains value for ***
- Maven载入包速度慢
- 最小生成树-Kruskal算法
- Hibernate初学小笔记1《2017-09-06》
- sqlalchemy学习笔记
- Poj1064:二分搜索+可行性判定问题
- 矩形覆盖
- Java并发编程:(4)volatile关键字的使用
- 阻止点击<a>标签链接跳转
- C# MQTT客户端--M2MQTT
- Metasploit启动时Failed to connect to the database