题目链接在这里
题目大意:
有n个点和m条边,问这m条边构成的最小生成树是不是唯一的。
思路分析:
看最小生成树是不是唯一的,就先构造一棵最小生成树,将它所用到的边都记录下来,删掉其中一条边,看用其它的边还能不能再构造一棵最小生成树。
代码如下:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <algorithm>
#define rep(i, x) for(int i = 0; i < x; ++i)
#define clr(x) memset(x, 0, sizeof(x))
using namespace std;
const int INF = 0x3f3f3f3f;
const int MaxN = 105;
int n, m, t;
struct Edge{
int x, y, index, val;
bool operator < (const Edge& e) const{
return val > e.val;
}
}edge[MaxN * MaxN];
int par[MaxN], r[MaxN];
int index[MaxN * MaxN];
priority_queue <Edge> que;
void init(){
clr(r);
rep(i, MaxN) par[i] = i;
}
int Find(int x){
if(x == par[x]) return x;
return par[x] = Find(par[x]);
}
void unite(int x, int y){
x = Find(x);
y = Find(y);
if(x == y) return;
if(r[x] < r[y]) par[x] = y;
else{
par[y] = x;
if(r[x] == r[y]) ++r[x];
}
}
bool check(int x, int y){
return Find(x) == Find(y);
}
int kruskal1(){
init();
int cnt = 0;
int ans = 0;
while(!que.empty()){
Edge e = que.top();
que.pop();
if(check(e.x, e.y)) continue;
ans += e.val;
index[cnt++] = e.index;
unite(e.x, e.y);
}
return ans;
}
int kruskal(){
init();
int ans = 0;
while(!que.empty()){
Edge e = que.top();
que.pop();
if(check(e.x, e.y)) continue;
ans += e.val;
unite(e.x, e.y);
}
int cnt = 0;
rep(i, n + 1)
if(par[i] == i) ++cnt;
if(cnt == 2) return ans;
return -1;
}
int main(){
scanf("%d", &t);
while(t--){
scanf("%d %d", &n, &m);
int x, y, val;
rep(i, m){
scanf("%d %d %d", &edge[i].x, &edge[i].y, &edge[i].val);
edge[i].index = i;
que.push(edge[i]);
}
int ans = kruskal1();
bool flag = true;
rep(i, n - 1){
rep(j, m){
if(index[i] == edge[j].index) continue;
que.push(edge[j]);
}
int tmp = kruskal();
if(tmp == ans){
puts("Not Unique!");
flag = false;
break;
}
}
if(flag) printf("%d\n", ans);
}
return 0;
}