最小生成树的两种方法
来源:互联网 发布:hadoop2.4.1源码下载 编辑:程序博客网 时间:2024/04/27 14:57
最小生成树问题的讲道理都是很直观的,让人一眼看得穿,然后再在模版上稍加改动就完成了。
一般来说Prim跟Kruskal方法都是能解题的。但是复杂度不一样。
Prim的时间复杂度是O(n^2),而Kruskal方法与给出的边的数量有关,复杂度为O(eloge)其实时间都是花在排序上了 。
1.Prim算法
简单来说,就是从一个点开始不断寻找,链接着其他相关点,每次加入一个距离最小的点。
其中low数组就是保存到其他点的距离,vis保证每个点只经过一次。
另外求最大生成树类似,只要将输入的数加上负号,最后输出的时候再加上负号。
#include<iostream>#include<string.h>using namespace std;#define N 105#define inf 0x3f3f3f3fint low[N],vis[N],G[N][N];int x,n,ans;int prim(){ int pos,minnum,result=0; memset(vis,0,sizeof(vis)); vis[1]=1;pos=1;//从第一个定点开始也可从指定定点开始 for(int i=1; i<=n; i++) { if(i!=pos)low[i]=G[pos][i];}//更新low数组 for(int i=1; i<n; i++)//再运行n-1次 { minnum=inf; for(int j=1; j<=n; j++) { if(vis[j]==0&&minnum>low[j]) { minnum=low[j]; pos=j; } }//if(minnum==inf)break;前面在加cnt变量,可以判断是否能成功生成最小生成树 result+=minnum;//找到最小值与下一点 vis[pos]=1; for(int i=1; i<=n; i++) { if(vis[i]==0&&low[i]>G[pos][i]) low[i]=G[pos][i]; }//更新low数组 } return result;}int main(){ while(cin>>n) { memset(G,inf,sizeof(G));//赋初始值inf for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) { cin>>x; G[i][j]=G[j][i]=x;//最大生成树则是把权值改成负数,最终结果再加个负号 } ans=prim(); cout<<ans<<endl; } return 0;}
2.Kruskal算法
首先相对Prim不同的是,这是一种针对边来解决问题的一种方法,因此,定义结构,保存边的两点,权重等信息。
另外,要求最小,必然对权重排序。
然后不断纳入新的联通分量的点。(并查集知识)
#include<iostream>#include<algorithm>using namespace std;struct Edge{ int u,v,w;} edge[105];//结构体包括边的两个连接点和权重int parent[105];int findpa(int x){ return parent[x]==x?x:findpa(parent[x]);}//查找是否在同一个连通分量中bool cmp(Edge a,Edge b){ return a.w<b.w;}//按权值排序void Init(){ for(int i=1; i<=105; i++) parent[i]=i;//开始每个都是一个单独的联通分量}int main(){ int n; cin>>n; Init(); for(int i=0; i<n; i++) cin>>edge[i].u>>edge[i].v>>edge[i].w; sort(edge,edge+n,cmp); int ans=0; for(int i=0; i<n; i++) { int x=findpa(edge[i].u); int y=findpa(edge[i].v); if(x!=y)//判断两点是否在同一个连通分量中,是就不要,不是就纳入 { parent[y]=x; ans+=edge[i].w; } } cout<<ans<<endl; return 0;}
前导知识:并查集
算法描述:并查集用来解决判断两个节点是否相连通,且不需要给出的具体路径(需要给路径另外考虑dfs等算法)
算法核心:指定唯一根节点,判断两节点是否有共同的根节点。单纯向上寻找可能很费时间,且因为不用保留路径因此可以使用路径压缩:既令同一个连通分量中的元素直接指向父节点。
核心代码 :简单模版void init()//一开始每个人都是独立一个连通分量{ cnt = 0; for (int i=0; i<=m; i++) p[i] = i;}int find(int x)//不断查找父节点{ return p[x]==x ? x : p[x] = find(p[x]);}void merge(int a, int b){ int pa = find(a), pb = find(b); p[pa] = pb; }
PS:关于最小生成树的基本上都是在模版上大致改动。准备一个好用的模版很重要~
0 0
- 最小生成树的两种方法
- 最小生成树的两种方法
- 最小生成树的两种实现
- 最小生成树的两种算法
- 图的最小生成树的两种算法
- 最小生成树的两种算法及模版整理
- 带你辨析最小生成树的两种算法
- 浅谈最小生成树的两种算法
- 最小生成树--两种常见的写法;
- 最小生成树的两种算法(Prim算法
- 【★】最小生成树的两大解法!
- 最小生成树(题解) 两种解法
- HDOJ-1102 Constructing Roads(最小生成树)两种做法
- POJ 2485 Highways 两种最小生成树算法
- hdu1301 Jungle Roads(两种基本最小生成树)
- POJ-1251 Jungle Roads 最小生成树 两种算法的简单模板
- 最小生成树的两种算法:Prim和Kruskal算法
- 最小生成树(minimum spanning tree)问题的两种解法
- Java TCP 简单实例
- 在win10上安装nodejs+npm+express+coffeescript
- vmware 连接外部设备
- 从头认识Spring-2.8 基于java注解的配置(基本没有xml)
- (8) linux shell 命令 -- cp
- 最小生成树的两种方法
- 循环链表
- SAX和DOM解析XML区别
- Xmanager4.0注册码
- apache漏洞修复(绿盟科技漏洞)
- HDU 4405 Aeroplane chess(概率DP)
- 学习笔记6
- 蓝桥杯 历届试题-九宫重排
- 位运算之位操作符