标签:set inf fine img 合并 show 最小生成树 一段 gif
借鉴博客: https://www.cnblogs.com/Howe-Young/p/4911992.html
https://www.cnblogs.com/bianjunting/p/10829212.html
一,定义
权值第 2 小的生成树。
二,Prim 算法
① 算法思想
1,在最小生成树构建的过程中 ,在合并树的时候,将两棵树之间 除加进来 的最小边以外的其他边都尝试加入,
选择一条最小是能够替换两个最小树之间的边,然后不断更新,最后得到答案。
② 步骤
1.先求出来最小生成树。在求 最小生成树 的时候一并将 最小生成树任意两点之间路径当中的权值最大的那一条 求出来。
求这个有什么用呢?
原来 最小生成树加入一条边之后一定构成了回路,所以如果说 加入了边 ij , 此时 i 到 j 有两条路,这两条路构成一个回路,
要想构成生成树的话,必然删除这条回路上的边,要想和原来不一样且最小,则删除原先 最小生成树上 i 到 j 路径中的最大边
2.尝试添加最小生成树外的每一条边,删除上面找到的边。其中的权值最小的就是次小生成树。
③ 代码
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #include<string.h> #define inf 0x3f3f3f3f #define MIN(x,y) (x<y?x:y) #define MAX(x,y) (x>y?x:y) #define N 105 int a[N][N]; //邻接矩阵存图 int max[N][N]; //表示最小生成树中 i 到 j 的最大边权 int used[N][N]; //判断该边是否加入最小生成树 int p[N]; // 路径 int dis[N]; // 集合 u 到 i 的最短距离 bool vis[N]; // 标记集合 u 的点 int n, m; // m 是边数, n 是点数 void init() { memset(vis, 0, sizeof(vis)); memset(dis, 0x3f, sizeof(dis)); memset(a, 0x3f, sizeof(a)); memset(p, 0, sizeof(p)); memset(used, 0, sizeof(used)); memset(max, 0, sizeof(max)); } int prim() // 求 最小生成树 { int s = 1; dis[1] = 0, vis[s] = 1, p[s] = 0; int sum = 0; for (int i = 1; i < n; i++) // 边数 为点数减一 { for (int j = 1; j <= n; j++) // 更新距离,标记起点 { if (vis[j] == 0 && dis[j] > a[s][j]) { dis[j] = a[s][j]; p[j] = s; } } int min = inf; for (int j = 1; j <= n; j++) // 找到 最小的那条边 { if (vis[j] == 0 && dis[j] < min) { min = dis[j]; s = j; } } if (min == inf) return -1; vis[s] = 1; sum += min; used[s][p[s]] = used[p[s]][s] = 1; for (int j = 1; j <= n; j++) // 多了这一段 { if (vis[j]) max[j][s] = max[s][j] = MAX(max[j][p[s]], dis[s]); } } return sum; } int smst(int minT) // 求 次小生成树 { int ans = inf; for (int i = 1; i <= n; i++) //枚举最小生成树之外的边 for (int j = i + 1; j <= n; j++) if (a[i][j] != inf && !used[i][j]) ans = MIN(ans, minT + a[i][j] - max[i][j]); if (ans == inf) return -1; return ans; } void solve() { int minT = prim(); // 最小生成树 if (minT == -1) { puts("Not Unique!"); return; } int secT = smst(minT); // 次小生成树 if (secT == minT) printf("Not Unique!\n"); else printf("%d\n",minT); } int main(void) { int t; scanf("%d", &t); while (t--) { init(); scanf("%d %d", &n, &m); for (int i = 0; i < m; i++) { int u, v, w; scanf("%d %d %d", &u, &v, &w); a[u][v] = a[v][u] = w; } solve(); } system("pause"); return 0; }
标签:set inf fine img 合并 show 最小生成树 一段 gif
原文地址:https://www.cnblogs.com/asdfknjhu/p/13252284.html