Description
Input
Output
Sample Input
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
Sample Output
3
Not Unique!
题目大意:判断一个连通图的最小生成树是否唯一。
解题思路:先求出原图的最小生成树的权值,然后再求出原图的次小生成树。如果次小生成树的权值和最小生成树的权值相同,则说明原图的最小生成树不唯一。
求次小生成树的方法:先求出原图的最小生成树,然后枚举每条不在最小生成树中的边ei(u,v),先在最小生成树中删除从u 到 v 路径上的权值最大的边,然后将边ei加入其中,求得此时生成树的权值Wi , 只要找出所有Wi中的最小值即是次小生成树的权值。
具体过程详见程序:
#include <iostream> #include<cstring> #include<algorithm> #include<string> #include<cmath> #include<vector> #include<cstdio> #define mem(a , b ) memset(a , b , sizeof(a)) using namespace std ; const int MAXN = 1e6 + 5 ; struct Edge { int from , to , w ; } e[MAXN] ; vector <int> G[105] ; vector <int> V ; int set[MAXN] ; bool vis[MAXN] ; // 标记边是否被访问 bool visd[MAXN] ; // 标记顶点是否被访问 int f[105][105] ; // 记录最小生成树中每个点对(u,v)之间路径的权值最大的边的权值 int W[105][105] ; int n , m ; int ans = 0 ; int find(int x) { int r = x ; while (r != set[r]) { r = set[r] ; } int t ; while (x != r) { t = set[x] ; set[x] = r ; x = t ; } return r ; } void chu() { int i ; for(i = 0 ; i <= n ; i ++) { set[i] = i ; G[i].clear() ; } mem(vis , 0) ; mem(f , 0) ; mem(visd , 0) ; mem(W , 0) ; V.clear() ; ans = 0 ; } bool cmp(Edge a , Edge b) { return a.w < b.w ; } void init() { scanf("%d%d" , &n , &m) ; chu() ; int i ; int a , b , c ; for(i = 0 ; i < m ; i ++) { scanf("%d%d%d" , &a , &b , &c) ; e[i].from = a ; e[i].to = b ; e[i].w = c ; } sort(e , e + m , cmp) ; int cnt = 0 ; for(i = 0 ; i < m ; i ++) { int tx , ty ; tx = e[i].from ; ty = e[i].to ; int x , y ; x = find(tx) ; y = find(ty) ; if(x != y) { G[tx].push_back(ty) ; G[ty].push_back(tx) ; W[tx][ty] = W[ty][tx] = e[i].w ; cnt ++ ; ans += e[i].w ; if(x < y) set[y] = x ; else set[x] = y ; vis[i] = true ; if(cnt == n - 1) break ; } } } void dfs(int u) // 求最小生成树中每个点对(u,v)之间的路径中权值最大的边的权值 { visd[u] = true ; V.push_back(u) ; int i ; for(i = 0 ; i < G[u].size() ; i ++) { int v = G[u][i] ; if(!visd[v]) { int j ; for(j = 0 ; j < V.size() ; j ++) { f[v][ V[j] ] = f[ V[j] ][v] = max(f[ V[j] ][u] , W[u][v]) ; } dfs(v) ; } } } void solve() { dfs(1) ; int tmp ; int i ; for(i = 0 ; i < m ; i ++) { if(!vis[i]) { int a , b ; a = e[i].from ; b = e[i].to ; tmp = ans ; tmp = ans + e[i].w - f[a][b] ; if(tmp == ans) { puts("Not Unique!") ; return ; } } } printf("%d\n" , ans) ; } int main() { int T ; scanf("%d" , &T) ; while (T --) { init() ; solve() ; } return 0 ; }