次小生成树 【总结】
2015-08-10 18:37
357 查看
MST - 最小生成树
引子:给你N个点以及M条边,问你MST是否唯一,若不唯一输出-1,否则输出MST的值。
通过 枚举 + 删边 + 再求MST 完全可以做到求解上述题目,但时间复杂度过高。这里介绍一种(N*2)的算法,是结合prime算法实现的。
算法核心思想:在prime求MST的过程中 用数组存储MST里面任意两点间的唯一的路中 权值最大的那条边的权值。最后枚举不在MST里面的边<i,,j>,判断<i,j>的权值 是否 和 MST里面 i 到 j 的最大权值相等,只要有一条边满足就可以说明MST不唯一。(因为我们可以用这条不在MST的边来 代替 在MST的边,这样MST肯定不唯一)
数组使用
prime 模版用到三个数组 low[] vis[] Map[][],不再详细解释。
MST[ i ][ j ] : 存储MST中i 到 j 的唯一的路中 权值最大的那条边的权值。
InMST[ i ][ j ] : 判断<i,j>这条边是否在MST中.
pre[ i ] : 记录 i 点的前驱 fa ,low[ i ] = Map[ fa ][ i ]。
对于选入MST的点next
MST更新:MST[ next ][ j ] = max(MST[ pre[ next ] ][ j ], low[ next ])。( j 属于MST里面的点)
代码实现:
测试数据:
输出:
引子:给你N个点以及M条边,问你MST是否唯一,若不唯一输出-1,否则输出MST的值。
通过 枚举 + 删边 + 再求MST 完全可以做到求解上述题目,但时间复杂度过高。这里介绍一种(N*2)的算法,是结合prime算法实现的。
算法核心思想:在prime求MST的过程中 用数组存储MST里面任意两点间的唯一的路中 权值最大的那条边的权值。最后枚举不在MST里面的边<i,,j>,判断<i,j>的权值 是否 和 MST里面 i 到 j 的最大权值相等,只要有一条边满足就可以说明MST不唯一。(因为我们可以用这条不在MST的边来 代替 在MST的边,这样MST肯定不唯一)
数组使用
prime 模版用到三个数组 low[] vis[] Map[][],不再详细解释。
MST[ i ][ j ] : 存储MST中i 到 j 的唯一的路中 权值最大的那条边的权值。
InMST[ i ][ j ] : 判断<i,j>这条边是否在MST中.
pre[ i ] : 记录 i 点的前驱 fa ,low[ i ] = Map[ fa ][ i ]。
对于选入MST的点next
MST更新:MST[ next ][ j ] = max(MST[ pre[ next ] ][ j ], low[ next ])。( j 属于MST里面的点)
代码实现:
#include <cstdio> #include <cstring> #include <algorithm> #define MAXN 100+10 #define INF 100000000 using namespace std; int Map[MAXN][MAXN]; bool vis[MAXN]; int low[MAXN];//上面三个数组 求MST 专用 int MST[MAXN][MAXN];//MST中 i 和 j的最大边权 int pre[MAXN];//记录前驱 bool InMST[MAXN][MAXN];//标记该边是否在MST中 int N, M; void init() { for(int i = 1; i <= N; i++) { Map[i][i] = 0; for(int j = 1; j < i; j++) Map[i][j] = Map[j][i] = INF; } } void getMap() { int a, b, c; for(int i = 1; i <= M; i++) { scanf("%d%d%d", &a, &b, &c); if(Map[a][b] > c) Map[a][b] = Map[b][a] = c; } } void solve() { //prime求MST int mincost = 0;//最小代价 int next, Min; memset(InMST, false, sizeof(InMST)); memset(MST, 0, sizeof(MST)); for(int i = 1; i <= N; i++) { low[i] = Map[1][i]; vis[i] = false; pre[i] = 1;//每个点前驱 } vis[1] = true; for(int i = 2; i <= N; i++) { Min = INF; next = -1; for(int j = 1; j <= N; j++) { if(!vis[j] && Min > low[j]) { next = j; Min = low[j]; } } mincost += Min; vis[next] = true; int fa = pre[next];//当前找到点的 前驱 InMST[next][fa] = InMST[fa][next] = true;//在MST中 for(int j = 1; j <= N; j++) { if(vis[j] && j != next)//MST中的点 MST[j][next] = MST[next][j] = max(MST[fa][j], low[next]); if(!vis[j] && low[j] > Map[next][j])//更新low { low[j] = Map[next][j]; pre[j] = next;//更新前驱 } } } //判断MST是否唯一 for(int i = 1; i <= N; i++) { for(int j = 1; j < i; j++) { if(Map[i][j] != INF && !InMST[i][j])//有边 且不在MST中 { if(Map[i][j] == MST[i][j]) { printf("-1\n"); return ; } } } } printf("%d\n", mincost); } int main() { while(scanf("%d%d", &N, &M) != EOF) { init(); getMap(); solve(); } return 0; }
测试数据:
3 3 1 2 1 2 3 2 3 1 3 4 4 1 2 2 2 3 2 3 4 2 4 1 2
输出:
3 -1
相关文章推荐
- Day1_HTML_总结
- JNA调用C语言动态链接库学习实践总结
- Enumeration与Iterator的对比,ArrayList与Vector的比较
- find、locate、whereis、which和type
- leetcode Remove Duplicates from Sorted Array
- 信息化的十年
- hdu 5351 规律+大数
- Myeclipse2015去空格和等号的代码补全
- DEVOPS 技能列表
- 直接部署java项目到tomcat服务器
- 【暑期基础3】D HDU 2056 Rectangles (几何)
- I - In Touch-Gym 100492I-水题
- Hadoop和大数据:60款顶级开源工具
- Mac系统自带的邮箱发送到Outlook变成乱码——解决方案
- 菜鸟vimer成长记——第2.4章、cmd-line模式
- java 线程基础学习
- 笔试测试题2
- 2015年8月10日 C语言 宏和快排
- tomcat内存设置
- Day1_HTML_多媒体标记