题意:
给你n个点,m条边,问你最小生成树是不是唯一的,如果唯一输出最小生成树的总权值大小,否则就输出“Not Unique!”
思路:
求一下次小生成树看一下是不是和最小生成树总权值大小一样即可。
关于求次小生成树:
求次小生成树
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <queue>
#include <stack>
using namespace std;
typedef long long LL;
const int MAXN = 100+5;
const int inf = 1e9;
int n,m;
struct edge
{
int u,v,w;
bool operator < (const edge &a)const
{
return w < a.w;
}
} edge[MAXN*MAXN];
int pre[MAXN<<1];
int findx(int x)
{
return pre[x] == x?x:pre[x] = findx(pre[x]);
}
bool vis[MAXN*MAXN];
void kruskal()
{
sort(edge,edge+m);
//首先求一次最小生成树
for(int i = 1; i <= n; ++i)pre[i] = i;
for(int i = 0; i < m; ++i)vis[i] = 0;
int min1 = 0;
int cnt = 0;
for(int i = 0; i < m; ++i)
{
int u = edge[i].u;
int v = edge[i].v;
int w = edge[i].w;
u = findx(u);
v = findx(v);
if(u != v)
{
pre[v] = u;
cnt++;
min1 += w;
vis[i] = 1;
if(cnt == n-1)break;
}
}
//寻找次小生成树
int min2 = inf;
//枚举不是在最小生成树中的边
for(int i = 0; i < m; ++i)
{
if(vis[i])continue;
//首先把当前边加入最小生成树中
int sum = 0;
for(int i = 1; i <= n; ++i)pre[i] = i;
pre[edge[i].v] = edge[i].u;
sum += edge[i].w;
//然后继续加边构成最小生成树
cnt = 1;
for(int j = 0; j < m; ++j)
{
int u = edge[j].u;
int v = edge[j].v;
int w = edge[j].w;
u = findx(u);
v = findx(v);
if(u != v)
{
pre[v] = u;
sum += w;
cnt++;
if(cnt == n-1)
{
min2 = min(min2,sum);
break;
}
}
}
}
if(min2 == min1)puts("Not Unique!");
else printf("%d\n",min1);
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(int i = 0; i < m; ++i)
{
scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
}
kruskal();
}
return 0;
}