1 /*for(遍历图中所有不属于最小生成树的边)
2 把当前边加入最小生成树产生回路
3 去掉回路中除当前边之外权值最大的边
4 记录下现在的树及其总权值
5 在上面循环产生的树中选一棵总权值最小的,就是次小生成树*/
6 /*上面做法只遍历一次最小生成树,但是如果枚举删去最小生成树上的边,那就要求n-2次最小生成树了,所以不可取*/
7 #include <cstdio>
8 #include <cstring>
9 #include <algorithm>
10 #include<queue>
11 using namespace std;
12 typedef pair<int,int> pii;
13 const int maxn = 111;
14 const int inf = 0x3f3f3f3f;
15 int g[maxn][maxn];//邻接矩阵存图
16 int Max[maxn][maxn];//表示最小生成树中i到j的最大边权
17 bool used[maxn][maxn];//判断该边是否加入最小生成树
18 int pre[maxn];//点在最小生成树上的前驱
19 int dis[maxn];//在已存的点集中,到各个点的最短边
20 bool vis[maxn];//判断该点是否加入最小生成树
21 int T,n,m;
22 int prim()
23 {
24 int sum= 0;
25 memset(vis, false, sizeof(vis));
26 memset(used, false, sizeof(used));
27 memset(Max, 0, sizeof(Max));
28 memset(dis,0x3f3f3f3f,sizeof(dis));
29 dis[1]=0;
30 pre[1]=0;
31 priority_queue<pii,vector<pii>,greater<pii> >q;
32 q.push(make_pair(0,1));
33 int all=0;
34 while(!q.empty()){
35 int u=q.top().second;
36 q.pop();
37 if(vis[u]) continue;
38 vis[u]=1;
39 //就是只有当我确定了u这个点进入了最小生成树,我才改used数组和Max,之间都只是根据dis修改pre;
40 used[u][pre[u]]=used[pre[u]][u]=1;
41 ++all;
42 sum+=dis[u];
43 for(int j=1;j<=n;++j){
44 if(vis[j]) {
45 if(j!=u) Max[j][u]=Max[u][j]=max(Max[j][pre[u]],dis[u]);
46 else Max[j][u]=0;
47 //相当于一个dp,求出j到u之间最长边的边权.
48 }
49 else if(g[j][u]!=0x3f3f3f3f&&dis[j]>g[j][u]){
50 dis[j]=g[j][u];
51 pre[j]=u;
52 q.push(make_pair(dis[j],j));
53 }
54 }
55 }
56 if(all<n) return -1;
57 return sum;//最小生成树的权值之和
58 }
59 int smst(int sum)//sum是最小生成树的权值和
60 {
61 int ans=0x3f3f3f3f;
62 for (int i = 1; i <= n; i++)//枚举最小生成树之外的边
63 for (int j = i + 1; j <= n; j++)
64 if (g[i][j]!=0x3f3f3f3f&&!used[i][j])
65 //加一条连接i和j(保证之后可以构成生成树)的且不在最小生成树的边,再删去i和j中最大边权的边
66 ans=min(ans,sum+g[i][j]-Max[i][j]);
67 if (ans==0x3f3f3f3f) return -1;
68 return ans;
69 }
70 int main()
71 {
72 scanf("%d", &T);
73 while (T--)
74 {
75 scanf("%d %d", &n, &m);
76 memset(g,0x3f3f3f3f,sizeof(g));
77 for(int i=1;i<=n;++i) g[i][i]=0;
78 int u,v,w;
79 for(int i=1;i<=m;++i){
80 scanf("%d%d%d",&u,&v,&w);
81 g[u][v]=g[v][u]=min(g[u][v],w);
82 }
83 int ans=prim();
84 if(ans==-1) puts("Not Unique!");
85 else if(smst(ans)==ans) puts("Not Unique!");
86 else printf("%d\n",ans);
87 //题目要判断最小生成树是否唯一
88 }
89 return 0;
90 }