题目链接:点击打开链接
思想:首先用prim算法求一遍最小生成树,在求的过程中维护一个数组max_len来存最小生成树中的点i到j这条路径上最大的一条边,为了维护这个数组还要记录每个最小生成树节点的前驱节点pre。然后遍历每一条不在树上的边e(i,j),比较e(i,j)和max_len[i][j]的大小,如果一样大说明可以有第二个最小生成树了,如果一直都找不到和它一样大的说明不存在。求次小生成树就是找到最小的max_len[i][j]-e[i][j]加到原来生成树的答案上面。
代码:(参考:点击打开链接)
#include<iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <cmath>
#include <queue>
#include <map>
using namespace std;
const int inf = 1000000005;
int grid[105][105],max_len[105][105],pre[105];
int vis[105],mincost[105];
int main(){
int T;
scanf("%d",&T);
while(T--){
int n,m;
scanf("%d%d",&n,&m);
int x,y,l;
for(int i=1; i<=n; i++){
for(int j=1; j<=n; j++){
grid[i][j] = grid[j][i] = inf;
}
}
for(int i=1; i<=m; i++){
scanf("%d%d%d",&x,&y,&l);
grid[x][y] = grid[y][x] = l;
}
for(int i=1; i<=n; i++) mincost[i] = inf;
mincost[1] = 0;
memset(vis,false,sizeof(vis));
memset(max_len,0,sizeof(max_len));
int ans = 0;
memset(pre,-1,sizeof(pre));
//求最初的最小生成树
while(true){
int p = -1;
for(int i=1; i<=n; i++){
if(vis[i]==false && (p == -1 || mincost[i]<mincost[p]) ) p = i;
}
if(p == -1) break;
vis[p] = true;
ans += mincost[p];
for(int i=1; i<=n; i++){
if(vis[i] && (i!=p)){
max_len[i][p] = max_len[p][i] = max(max_len[pre[p]][i], mincost[p]);
}
}
for(int i=1; i<=n; i++){
if(vis[i] == false && mincost[i]>grid[p][i]){
mincost[i] = grid[i][p];
pre[i] = p;
}
}
}
int tmp = inf;
for(int i=1; i<=n; i++){
for(int j=1; j<=n; j++){
//如果这条边不在最小生成树内
if(i!=j && pre[i]!=j && pre[j]!=i){
tmp = min(tmp, grid[i][j] - max_len[i][j]);
}
}
}
//cout<<ans<<endl;
if(tmp == 0) printf("Not Unique!\n");
else printf("%d\n",ans);
}
return 0;
}