POJ 1679 The Unique MST (次小生成树)

时间:2020-12-14 20:42:23

题目链接:http://poj.org/problem?id=1679

有t组数据,给你n个点,m条边,求是否存在相同权值的最小生成树(次小生成树的权值大小等于最小生成树)。

先求出最小生成树的大小,把最小生成树的边存起来。然后分别枚举最小生成树上的每条边,除了这条边,其他边是否能生成最小生成树,若生成树的权值等于原来最小生成树的权值,则不唯一,否则输出最小生成树的权值。这里我用kruskal比较方便。

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int MAXN = ;
const int INF = 1e9;
struct edge {
int u , v , cost;
}a[MAXN * MAXN];
typedef pair <int , int> P;
int par[MAXN] , f;
bool vis[MAXN][MAXN];
vector <P> G; void init(int n) {
for(int i = ; i <= n ; i++) {
par[i] = i;
}
memset(vis , false , sizeof(vis));
f = ;
G.clear();
} bool cmp(edge a , edge b) {
return a.cost < b.cost;
} int Find(int n) {
if(par[n] == n)
return n;
return (par[n] = Find(par[n]));
} int kruskal(int m , int n) {
int res = , cont = n;
for(int i = ; i <= m ; i++) {
if(cont == )
break;
else if(vis[a[i].u][a[i].v])
continue;
int u = Find(a[i].u) , v = Find(a[i].v);
if(u != v) {
if(!f) {
G.push_back(P(a[i].u , a[i].v)); // f等于0的时候是求最小生成树的时候,存边操作
}
par[u] = v;
res += a[i].cost;
cont--;
}
}
if(cont == )
return res;
return INF;
} int main()
{
int t , n , m , u , v , w;
scanf("%d" , &t);
while(t--) {
scanf("%d %d" , &n , &m);
init(n);
for(int i = ; i <= m ; i++) {
scanf("%d %d %d" , &u , &v , &w);
a[i].u = u , a[i].v = v , a[i].cost = w;
}
sort(a + , a + m + , cmp);
int res = kruskal(m , n) , check = ;
f++;
for(int i = ; i < G.size() ; i++) {
for(int j = ; j <= n ; j++) {
par[j] = j;
}
vis[G[i].first][G[i].second] = true;
if(res == kruskal(m , n)) {
check = ;
break;
}
vis[G[i].first][G[i].second] = false;
}
if(check) {
printf("Not Unique!\n");
}
else {
printf("%d\n" , res);
}
}
}