最小生成树基础上,在添加边的时候,多处理一个len。。。len【i】【j】表示从i到j成环的时候应该删除这个环里最长的边的边长,其实就是每次加边时候,如果边的两边两个点uv祖宗不相连,那么加这条边,这条边是当前最大的边,就是说,u的祖宗和v的祖宗所链接的点及自己(最初加边时加自己到自己的边)互相之间的len都是现在这条边的权值。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 210;
const int maxm = maxn*maxn;
int n,m,tt,tot ,root[maxn];
int len[maxn][maxn],head[maxn];
bool vis[maxn][maxn];
char c[2];
struct node{
int from,to,w;
bool operator < (const node &b)const{
return w < b.w;
}
}edges[maxm];
struct no{
int v,next;
}eg[maxm];
void add(int u,int v){
eg[tt].v = v;eg[tt].next=head[u];head[u]=tt++;
}
void init(){
scanf("%d%d",&n,&m);
memset(vis,false,sizeof(vis));
memset(head,-1,sizeof(head));
tot = tt = 0;
for(int i = 0; i <= n ; i++) root[i] = i;
for(int i = 1 ; i <= m ; i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v);
add(u,u);
edges[tot].from = u;edges[tot].to = v;edges[tot].w = w;
tot++;
}
sort(edges,edges+tot);
}
int findroot(int x){
return x==root[x]?x:root[x]=findroot(root[x]);
}
void kru(){
int ans = 0;
for(int i = 0 ; i < tot ;i++){
int x = findroot(edges[i].to),y = findroot(edges[i].from);
if(x == y) continue;
else{
ans+=edges[i].w;
vis[edges[i].from][edges[i].to] = true;
for(int s1 = head[x];s1!=-1;s1 = eg[s1].next)
for(int s2 = head[y];s2!=-1;s2 = eg[s2].next)
len[eg[s1].v][eg[s2].v] = len[eg[s2].v][eg[s1].v]=edges[i].w;
root[x] = root[y];
}
}
//printf("ans = = %d\n",ans);
int semst = (1<<30);
for(int i = 0; i < tot ; i++){
if(!vis[edges[i].from][edges[i].to]){//加入这条没在mst里面的边
semst = min(semst,ans-len[edges[i].from][edges[i].to]+edges[i].w);
// cout << "semet = "<<semst <<endl;
}
}
if(semst == ans) printf("Not Unique!\n");
else printf("%d\n",ans);
}
int main(){
int T;
scanf("%d",&T);
while(T--){
init();
kru();
}
}