最小生成树&&次小生成树
2015-11-11 21:47
190 查看
习题链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=85800#overview
密码xwd
关于生成树的定义:设图 G=(V, E) 是个连通图,当从图任一顶点出发遍历图G 时,将边集 E(G) 分成两个集合 T(G) 和 B(G)。其中 T(G)是遍历图时所经过的边的集合,B(G) 是遍历图时未经过的边的集合。显然,G1(V, T) 是图 G 的极小连通子图,即子图G1 是连通图 G 的生成树。
生成树的用处很多,下面介绍一下最小生成树。
顾名思义,最小生成树即边权和最小的生成树。假如我们在游玩,那么从一个景点出发到其他所有的景点获取最短的路径是很excited的。这就涉及到了最小生成建树的问题。
获得最小生成树的算法有很多,其中最常用的是kruskal和prim算法。
kruskal算法俗称破圈法,是一个贪心算法的典型例子。kruskal算法的思想是将所有的边排序,紧接着在这些边中取最小权值的边,并判断它双向的点是否连通以及是否成环。这样扫描一遍所有的边即可获得最小生成树。
对kruskal算法的证明:
如何判断无向图是否成环?这里介绍一个很巧妙很实用的数据结构:并查集。
顾名思义,并查集是对一个集合进行维护的数据结构,它包含了两种基本操作:并和查(- -)
代码:
pre数组存放的是角标为序号的节点的父节点(初始化将所有节点的父节点设置为自己)。查询节点的父节点时可以递归地调用find函数,不断更新和查找父节点。直到自己是自己的父亲为止。并查集看起来很像一个森林。并的操作更简单了,只要看看两个元素的父节点是否相同,如果不相同那么任意合并一个到另一个树上即可。
回到kruskal算法,kruskal正是使用了这个精巧的数据结构维护了所有点的连通性。代码如下:
验题:poj2349
View Code
关于次小生成树,我们可以首先求出最小生成树,然后将最小生成树上的边依次取下。向上添加其他的边,这样就可以求得次小生成树了。可以看这一个题解:http://www.cnblogs.com/vincentX/p/4946099.html
转载请声明出处及作者,谢谢。
密码xwd
关于生成树的定义:设图 G=(V, E) 是个连通图,当从图任一顶点出发遍历图G 时,将边集 E(G) 分成两个集合 T(G) 和 B(G)。其中 T(G)是遍历图时所经过的边的集合,B(G) 是遍历图时未经过的边的集合。显然,G1(V, T) 是图 G 的极小连通子图,即子图G1 是连通图 G 的生成树。
生成树的用处很多,下面介绍一下最小生成树。
顾名思义,最小生成树即边权和最小的生成树。假如我们在游玩,那么从一个景点出发到其他所有的景点获取最短的路径是很excited的。这就涉及到了最小生成建树的问题。
获得最小生成树的算法有很多,其中最常用的是kruskal和prim算法。
kruskal算法俗称破圈法,是一个贪心算法的典型例子。kruskal算法的思想是将所有的边排序,紧接着在这些边中取最小权值的边,并判断它双向的点是否连通以及是否成环。这样扫描一遍所有的边即可获得最小生成树。
对kruskal算法的证明:
对于一个无向加权连通图,总是存在一棵或以上的有限课生成树,而这些生成树中肯定存在至少一棵最小生成树。下面证明Kruskal算法构造的生成树是这些最小生成树中的一棵。 设T为Kruskal算法构造出的生成树,U是G的最小生成树。如果T==U那么证明结束。如果T != U,我们就需要证明T和U的构造代价相同。由于T != U,所以一定存在k > 0条边存在于T中,却不在U中。接下来,我们做k次变换,每次从T中取出一条不在U中的边放入U,然后删除U一条不在T中的边,最后使T和U的边集相同。每次变换中,把T中的一条边e加入U,同时删除U中的一条边f。e、f按如下规则选取:a). e是在T中却不在U中的边的最小的一条边;b). e加入U后,肯定构成唯一的一个环路,令f是这个环路中的一条边,但不在T中。f一定存在,因为T中没有环路。 这样的一次变换后,U仍然是一棵生成树。 我们假设e权值小于f,这样变换后U的代价一定小于变换前U的代价,而这和我们之前假设U是最小生成树矛盾,因此e权值不小于f。 再假设e权值大于f。由于f权值小于e,由Kruskal算法知,f在e之前从E中取出,但被舍弃了。一定是由于和权值小于等于f的边构成了环路。但是T中权值小于等于f(小于e)的边一定存在于U中,而f在U中却没有和它们构成环路,又推出矛盾。所以e权值不大于f。于是e权值等于f。 这样,每次变换后U的代价都不变,所以K次变换后,U和T的边集相同,且代价相同,这样就证明了T也是最小生成树。由证明过程可以知道,最小生成树可以不是唯一的。
如何判断无向图是否成环?这里介绍一个很巧妙很实用的数据结构:并查集。
顾名思义,并查集是对一个集合进行维护的数据结构,它包含了两种基本操作:并和查(- -)
代码:
int pre[maxn]; int N, d; int find(int x) { return x == pre[x] ? x : pre[x] = find(pre[x]); } void unite(int x, int y) { x = find(x); y = find(y); if(x != y) { pre[y] = x; } } inline void init() { for(int i = 0; i < maxn; i++) { pre[i] = i; } }
pre数组存放的是角标为序号的节点的父节点(初始化将所有节点的父节点设置为自己)。查询节点的父节点时可以递归地调用find函数,不断更新和查找父节点。直到自己是自己的父亲为止。并查集看起来很像一个森林。并的操作更简单了,只要看看两个元素的父节点是否相同,如果不相同那么任意合并一个到另一个树上即可。
回到kruskal算法,kruskal正是使用了这个精巧的数据结构维护了所有点的连通性。代码如下:
验题:poj2349
#include <algorithm> #include <iostream> #include <iomanip> #include <cstring> #include <climits> #include <complex> #include <fstream> #include <cassert> #include <cstdio> #include <bitset> #include <vector> #include <deque> #include <queue> #include <stack> #include <ctime> #include <set> #include <map> #include <cmath> using namespace std; const int maxn = 105; const int inf = 0xffffff; int d[maxn]; int G[maxn][maxn]; int vis[maxn]; int n, m; //n:vertex m:edge void init() { memset(vis, 0, sizeof(vis)); for(int i = 0; i <= n; i++) { d[i] = inf; for(int j = 0; j <= n; j++) { G[i][j] = G[j][i] = inf; } G[i][i] = 0; } } int prim(int start) { d[start] = 0; for(int i = 1; i <= n; i++) { int u = -1; for(int j = 1; j <= n; j++) { if(!vis[j]) { if(u == -1 || d[j] < d[u]) { u = j; } } } vis[u] = 1; for(int j = 1; j <= n; j++) { if(!vis[j]) { d[j] = min(G[u][j], d[j]); } } } int sp = 0; for(int i = 1; i <= n; i++) { sp += d[i]; } return sp; } int main() { // freopen("in", "r", stdin); int u, v, w; while(~scanf("%d %d", &n, &m) && n) { init(); while(m--) { scanf("%d %d %d", &u, &v, &w); if(w < G[u][v]) { G[u][v] = G[v][u] = w; } } printf("%d\n", prim(1)); } }
View Code
关于次小生成树,我们可以首先求出最小生成树,然后将最小生成树上的边依次取下。向上添加其他的边,这样就可以求得次小生成树了。可以看这一个题解:http://www.cnblogs.com/vincentX/p/4946099.html
转载请声明出处及作者,谢谢。
相关文章推荐
- Win8Metro(C#)数字图像处理--2.40二值图像轮廓提取
- 夺命雷公狗---Redis---2-Redis数据结构
- Linux下安装PHP
- 排序算法-选择排序_堆排序
- hdu1141
- 避免在EditText中验证日期
- jquery easyui-datagrid 如何清空数据
- 高效开发Android App的10个建
- linux——Shell的控制结构(附shell编写代码和运行结果)
- ViewPager中切换界面Fragment被销毁解析
- Deep Learning(深度学习)学习笔记整理系列之常用模型
- HashMap
- pthread primer 学习手记
- jquery.edatagrid(可编辑datagrid)的使用
- [Leetcode]Rotate List
- python封装screenrecord成一个录屏工具,并输出gif图
- 05 集群安装(stand alone)
- c++ primer第五版(中文)习题答案 第三章第五节-数组
- responsrializer-afn
- 从头认识java-8.3 内部类的.this和.new语法