次小生成树
来源:互联网 发布:广州锋泽网络垃圾 编辑:程序博客网 时间:2024/05/21 11:27
最小生成树的算法想必大家都很了解,主要有kruskal和prim。但如果要求次小生成树(即第二小的生成树)呢?
一种容易想到的方法是枚举删除最小生成树上的边,再求最小生成树。用kruskal这种算法的复杂度为O(n*elog2e),当图比较稠密时,复杂度接近O(n^3)。
但有一种更简单的方法:先求最小生成树T,枚举添加不在T中的边,则添加后一定会形成环。找到环上边值第二大的边(即环中属于T中的最大边),把它删掉,计算当前生成树的权值,取所有枚举修改的生成树的最小值,即为次小生成树。
这种方法在实现时有更简单的方法:首先求最小生成树T,然后从每个结点u遍历最小生成树T,用一个二维数组max[u][v]记录结点u到结点v的路径上边的最大值(即最大边的值)。然后枚举不在T中的边(u,v),计算T- max[u][v] + w(u,v)的最小值,即为次小生成树的权值。显然,这种方法的时间复杂度为O(n^2 + e)。
例:判断生成树的唯一性,唯一则输出权值,不唯一输出Not Unique!(POJ1679)
显然,可以转化为求次小生成树,次小生成树权值=最小生成树,则不唯一。
#include <iostream>#include <algorithm>#include <queue>const int INF = 0x7fffffff;const int MAX = 10001;int n,m;int num;int p[MAX];int max[101][101];struct Edge //原始图{ int from; int to; int w; bool flag;}e[MAX];struct Tree //最小生成树{ int to; int w; int next;}tree[202];int index[101];struct Node //生成树的结点{ int seq; //结点编号 int max; //从某个点到它的路径中的最大边的长度};bool cmp(const Edge &a, const Edge &b){ return a.w < b.w;}void makeSet(){ for(int i = 0; i <= n; i++) { p[i] = i; }}int findSet(int x){ if(x != p[x]) p[x] = findSet(p[x]); return p[x];}void addEdge(int from, int to, int w){ tree[num].to = to; tree[num].w = w; tree[num].next = index[from]; index[from] = num++;}int kruscal(){ int i,j; int x, y; int edgeNum = 0; int result = 0; makeSet(); std::sort(e,e+m,cmp); for(i = 0; i < m; i++) { x = findSet(e[i].from); y = findSet(e[i].to); if(x != y) { edgeNum++; addEdge(e[i].from,e[i].to,e[i].w); addEdge(e[i].to,e[i].from,e[i].w); e[i].flag = true; p[x] = y; result += e[i].w; } } return edgeNum == n-1 ? result : -1;}void bfs(int p){ int i,j; bool used[101]; memset(used,0,sizeof(used)); std::queue<Node> que; Node now,adj; now.max = 0; now.seq = p; que.push(now); used[p] = true; while(!que.empty()) { Node q = que.front(); que.pop(); for(i = index[q.seq]; i != -1; i = tree[i].next) { adj.seq = tree[i].to; adj.max = tree[i].w; if(!used[adj.seq]) { if(q.max > adj.max) adj.max = q.max; max[p][adj.seq] = adj.max; used[adj.seq] = true; que.push(adj); } } }}void second_MST(){ int i,j; int mst = kruscal(); for(i = 1; i <= n; i++) bfs(i); int smst = INF; for(i = 0; i < m; i++) { if(!e[i].flag) { if(mst + e[i].w - max[e[i].from][e[i].to] < smst) smst = mst + e[i].w - max[e[i].from][e[i].to]; } } if(smst == mst) printf("Not Unique!\n"); else printf("%d\n",mst);}int main(){ int i,j; int cases; int a,b,w; scanf("%d",&cases); while(cases--) { scanf("%d %d",&n,&m); for(i = 0; i < m; i++) { scanf("%d %d %d",&e[i].from,&e[i].to,&e[i].w); e[i].flag = false; } num = 0; memset(index,-1,sizeof(index)); second_MST(); } return 0;}
0 0
- 次小生成树
- 次小生成树
- 次小生成树
- 次小生成树
- 次小生成树
- 次小生成树
- 次小生成树
- 次小生成树
- 次小生成树
- 次小生成树
- 次小生成树
- 次小生成树
- 次小生成树
- 次小生成树
- 次小生成树
- 次小生成树
- 次小生成树
- 次小生成树
- 关闭浏览器后Session失效原因分析
- KMP算法小结
- svn原理----revert,回滚
- 短网址(短链)实现唤起App
- MSSQL中存储过程的可选参数的定义和使用_SQL高亮显示
- 次小生成树
- Java的四种引用,强弱软虚,用到的场景。
- 解决Xcode 8 Console 输出系统网络连接log的问题
- 打印自身源代码的程序
- C/C++进阶学习笔记(三) 异常处理 try catch throw
- Recast & Detour 寻路引擎的基本流程
- 一张图说明进程, 线程, 操作系统内存管理
- 第一节-数据结构
- Collections集合框架工具类