-
题目描述:
-
最小生成树大家都已经很了解,次小生成树就是图中构成的树的权值和第二小的树,此值也可能等于最小生成树的权值和,你的任务就是设计一个算法计算图的最小生成树。
-
输入:
-
存在多组数据,第一行一个正整数t,表示有t组数据。
每组数据第一行有两个整数n和m(2<=n<=100),之后m行,每行三个正整数s,e,w,表示s到e的双向路的权值为w。
-
输出:
-
输出次小生成树的值,如果不存在输出-1。
-
样例输入:
-
2 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
-
样例输出:
-
4 6
思路:
求给定图的次小生成树。
对于给定的图,我们可以证明,次小生成树可以由最小生成树变换一边得到。那么我们可以如下求给定图的次小生成树。首先,我们用prime算法求出图的最小生成树,在这个过程中记录每条边是否用过,以及两个点之间最短路径上的最大权值F[i,j]
F[i,j]可以如此求得,当加入点u的时候,并且u的父结点是v 那么对于已经在生成树中的节点x
F[x,u] = max(F[x,v], weight[u][v]),那么我么就可以用Prime算法一样的时间复杂度来求出图的次小生成树。
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define INF 0x3f3f3f3f
int T, n, m;
int G[110][110], F[110], M[110][110], mark[110];
int max(int x, int y) {
return x > y ? x : y;
}
void dfs(int src, int pre, int now) {
if (mark[now]) return;
//printf("dfs %d %d\n", src, now);
if (src == now) {
M[src][now] = M[now][src] = 0;
}else {
M[src][now] = max(G[pre][now], M[src][pre]);
M[now][src] = M[src][now];
//printf("update M(%d,%d) = %d\n", now, src, M[src][now]);
}
mark[now] = 1;
int i;
for (i=1; i<=n; i++)
if (F[i] == now || F[now] == i) {
dfs(src, now, i);
}
}
int main()
{
scanf("%d", &T);
while (T--) {
scanf("%d%d", &n, &m);
memset(G, INF, sizeof G);
int i, j;
for (i=0; i<m; i++) {
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
G[a][b] = G[b][a] = c;
}
// prim
int dist[110], min_sum=0;
memset(dist, INF, sizeof dist);
memset(F, -1, sizeof F);
memset(mark, 0, sizeof mark);
dist[1] = 0;
while (1) {
j = 0;
for (i=1; i<=n; i++)
if (!mark[i] && dist[i] < dist[j]) j = i;
if (j == 0) break;
min_sum += dist[j];
mark[j] = 1;
for (i=1; i<=n; i++)
if (!mark[i] && dist[i] > G[j][i]) {
dist[i] = G[j][i];
F[i] = j;
}
}
// now we get the max_path of i to j
memset(M, 0, sizeof M);
for (i=1; i<=n; i++) {
memset(mark, 0, sizeof mark);
dfs(i, i, i);
}
int ans = INF;
// try delete i-j
for (i=1; i<=n; i++)
for (j=1; j<=n; j++) {
if (i!=j && F[j] != i && F[i] != j && min_sum + G[i][j] - M[i][j] < ans) {
ans = min_sum + G[i][j] - M[i][j];
//printf("ans : min_sum + G[%d][%d] - M[%d][%d] = %d\n", i, j, i, j, ans);
}
}
printf("%d\n", ans);
}
return 0;
}
/**************************************************************
Problem: 1249
User: warcraftw
Language: C
Result: Accepted
Time:20 ms
Memory:1008 kb
****************************************************************/