次小生成树
求最小生成树时,用数组Max[i][j]来表示MST中i到j的最大边权。
求完后,直接枚举所有不在MST中的边,替换掉最大边权的边,更新答案。
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 110; const int INF = 1e9; bool vis[maxn]; int d[maxn]; int pre[maxn]; int Max[maxn][maxn]; bool used[maxn][maxn]; int g[maxn][maxn]; int n, m; int Prim() { int ans = 0; memset(vis, false, sizeof vis ); memset(Max, 0, sizeof Max ); memset(used, false, sizeof used ); vis[0] = true; pre[0] = -1; for(int i=1; i<n; ++i) { d[i] = g[0][i]; pre[i] = 0; } for(int i=1; i<n; ++i) { int p = -1; for(int j=0; j<n; ++j) if(!vis[j] && (p==-1||d[p]>d[j])) p = j; if(-1==p) return -1; ans += d[p]; vis[p] = true; used[p][pre[p]] = used[pre[p]][p] = true; for(int j=0; j<n; ++j) { if(vis[j]) Max[j][p] = Max[p][j] = max(Max[j][pre[p]], d[p]); if(!vis[j]&&d[j]>g[p][j]) { d[j] = g[p][j]; pre[j] = p; } } } return ans; } void solve() { int res = Prim(); if(-1 == res) { //图不连通 puts("Not Unique!"); return ; } int Mn = INF; for(int i=0; i<n; ++i) for(int j=i+1; j<n; ++j) if(g[i][j]!=INF && !used[i][j]) { Mn = min(Mn, g[i][j]-Max[i][j]); } if(Mn==INF || Mn!=0){ //不存在次小生成树 或 不相等 printf("%d\n", res); }else { puts("Not Unique!"); } } int main() { int T; scanf("%d", &T); while(T--) { scanf("%d%d", &n, &m); for(int i=0; i<n; ++i) for(int j=0; j<n; ++j) g[i][j] = INF; int x, y, z; while(m--) { scanf("%d%d%d", &x, &y, &z); x--; y--; g[x][y] = g[y][x] = z; } solve(); } return 0; }
时间: 2024-10-15 14:12:32