最小生成树学习
来源:互联网 发布:上海平面设计培训知乎 编辑:程序博客网 时间:2024/05/16 01:44
概述:
在一给定的无向图G = (V, E) 中,(u, v) 代表连接顶点 u 与顶点 v 的边(即),而 w(u, v) 代表此边的权重,若存在 T 为 E 的子集(即)且为无循环图,使得 w(T) 最小,则此 T 为 G 的最小生成树。
最小生成树其实是最小权重生成树的简称。
最小生成树:
一个无向连通图G=(V,E),最小生成树就是联结所有顶点的边的权值和最小时的子图T,此时T无回路且连接所有的顶点,所以它必须是棵树。
应用:
网络G表示n个城市之间的通信线路网线路(其中顶点表示城市,边表示两个城市之间的通信线路,边上的权值表示线路的长度或造价)。可通过求该网络的最小生成树达到求解通信线路或总代价最小的最佳方案。
如何求最小生成树呢?
一是Kruskal算法,另一种是Prim算法,这两种算法都使用了贪心策略。
涉及到的几个概念:
安全边:A是G的某最小生成树的子集,如果AU{(u,v)}仍是G的某最小生成树的子集,则(u,v)是安全边;
割:无向图G=(V, E)对V的一个划分(S, V-S);
边(u,v)通过割(S,V-S):(u,v)一个顶点位于S中,另一个顶点位于V-S中;
不妨害A的割:A中没有任意一条边通过该割;
轻边(light edge):通过割的所有边中权值最小的边(可能有多条)。
最小生成树生成的伪代码:
GENERIC-MST(G, w) A=空集 while A does not form a spanning tree(如果A不能构成一个生成树) do find an edge(u,v) that is safe for A(找A的安全边) A=AU{(u,v)} return A
算法导论定理:
G=(V,E) 是个无向连通加权图。A 是 E 的一个子集,它包含于 G 的某个最小生成树中。设割 (S, V-S) 是G的任意一个不妨害A的割(就是说A中任何一条边的两个端点要么全在S中,要么全在V-S中),边(u,v)是通过割(S,V-s)的一条轻边(就是说
(u,v)是所有端点分布于S和V-S的边中权值最小的),则(u,v)对集合A是安全的。
推论:
A是G=(V,E)的某个最小生成树的子集。G(A)=(V,A)是图G的一个森林(只有A集合中的边),C=(Vc, Ec)为G(A)的一个连通分支(森林中的树)。如果边(u,v)是连接C和G(A)中其他某连通分支的一条轻边,则(u,v)对集合A来说是安全的。
伪代码实现:
Kruskal 算法
MST-KRUSKAL(G, w) A=空集 for each vertex v∈V[G] do MAKE_SET(v) sort the edges of E into nondescreasing order by weight w for each edge(u,v)∈E, take in nondescreasing order by weight do if FIND-SET(u) != FIND-SET(v)// 如果u和v不在同一个连通分支中,就把(u,v)加入,由推论可知此边是安全的 then A = AU{(u,v)} UNION(u,v) return A
(FIND-SET(u)是找出u所在的连通分支。Kruskal在全局中找权值最小的边,然后判断此边是否“合法”,进行取舍,直到遍历完所有的边。Kruskal算法的运行时间为O(ElgV)。)
Prim算法(Prim适用于稠密图,对于给定坐标求最小生成树的题目再合适不过。)
MST-PRIM(G, w, r) for each u∈V[G] do key[u]=∞ π(u) = NIL // π(u)是u的前趋 key[r] = 0 Q=V[G] while Q != 空集 do u=EXTRACT-MIN(Q) for each v∈Adj[u] do if v∈Q and w(u,v)<key[v] then π(v)=u key[v] = w(u,v) // 更新key[v]</span></span>
(Q是一个优先队列,key[v]是所有将v与树中某一顶点相连的边中的最小权值,若不存在这样的边,则k[v]=∞。Prim算法在局部寻找权值小的的边(此边必合法),直到遍历完所有的节点。Prim算法的运行时间为O(ElgV),与Kruskal算法渐近相等。Prim算法实际上使用了与Dijkstra算法同样的策略,维护了一个权值数组key,在迭代过程中不断的更新。)
-------------------------------------------------------
代码:
/*Kruskal算法*/int cmp(const int i,const int j){ return w[i] < w[j];}int find(int x){ return p[x] == x ? x : p[x] = find(p[x]);}int Kruskal(){ int ans = 0; for(int i=0; i<n; i++) p[i] = i;//初始化并查集 for(int i=0; i<m; i++) r[i] = i;//初始化边序号 sort(r,r+m,cmp);//给边排序 for(int i=0; i<m; i++) { int e = r[i]; int x = find(u[e]); int y = find(v[e]);//找出当前边的两个端点所在的集合 if(x != y)//如果不在同集合,合并 { ans += w[e]; p[x] = y; } } return ans;}
/*prim算法*/int map[MAXN][MAXN];int low[MAXN];int vis[MAXN];int prim(){ int k,pos,minn; int result = 0; memset(vis,0,sizeof(vis)); pos = 1; vis[pos] = 1; for(int i=1; i<=n; i++) { if(i != pos) low[i] = map[pos][i]; } for(int i=1; i<n; i++) { minn = 100000000; for(int j=1; j<=n; j++) { if(!vis[j] && minn > low[j]) { minn = low[j]; pos = j; } } result += minn; vis[pos] = 1; for(int j=1; j<=n; j++) { if(!vis[j] && map[pos][j]<low[j]) low[j] = map[pos][j]; } } return result;}
以后加。。。。。。。。。。。。。。。。
----------------------------------------------------------------------------------------------
来源:点击打开链接
- 最小生成树学习
- 最小生成树学习总结
- 图的最小生成树学习笔记
- 图论中最小生成树的问题学习
- 最小生成树[Kruskal&&Prim](学习)
- 北大暑期学习之最小生成树
- 最小生成树问题学习总结
- 最小生成树Prim算法学习
- 最小生成树Kruskal算法学习
- 最小比例 最小生成树
- HDU 1301 最小生成树,以及最小生成树的学习
- 最小生成树&&次最小生成树
- 最小生成生成树计数
- 学习笔记--最小生成树之prim算法
- 学习笔记--最小生成树之kruskal算法
- 【学习笔记----数据结构19-图的最小生成树】
- 算法学习之图的最小生成树Kruskal算法
- 算法学习之最小生成树prim算法
- 如何将ucosii移植到vs2008中运行
- LTE相关术语解释
- 自己写的委托例子
- LeetCode Scramble String
- 【C++】泛型算法里的fill()函数用法
- 最小生成树学习
- Android 获取屏幕参数 高度 宽度
- Python编程风格和设计模式
- 按生辰八字给马宝宝取名的注意事项
- java 程序简单流程
- libcurl
- 怎么畅玩CSOL2韩服E9加速器分享
- Linux解压命令大全
- 小扎1