这题是输入一些边然后判断这些边的最小生成树是否唯一,那么我们可以找次小生成树,看看和最小生成树权值是否相同。这里是基于kruskal的次小生成树模板
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <stack>
#include <algorithm>
#include <cmath>
#include <vector>
#include <set>
#include <map>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=1e2;
struct P
{
int x,y,cost,vis;//vis标记是否是最小生成树的边
bool operator<(const P &a)const
{
return cost<a.cost;
}
} p[maxn*maxn+2];
int t,n,m;
int f[maxn];
vector<int> g[maxn];
int dis[maxn][maxn];
int Find(int x)
{
if(x==f[x]) return x;
else return f[x]=Find(f[x]);
}
void kruskal()
{
for(int i=0; i<=n; i++)
{
f[i]=i;
g[i].push_back(i);
}
sort(p+1,p+1+m);
int MST=0;
for(int i=1; i<=m; i++)//这个循环可以在边界条件上加一个num<n-1,用来剪枝,因为最小生成树只有n-1条边,再往后没有意义
{
int a=Find(p[i].x);
int b=Find(p[i].y);
if(a!=b)
{
for(int j=0; j<g[a].size(); j++)//这两层循环是用来找出成环前已经连接的点之间的最大的边,g[a]表示已经添加进最小生成树的点集,g[b]表示正要添加
{//到最小生成树的点集,连起来后a,b中的点两两可达,两两间最大边是当前加进去的边
for(int k=0; k<g[b].size(); k++)
{
int x=g[a][j];
int y=g[b][k];
dis[x][y]=dis[y][x]=p[i].cost;//更新最大的边
}
}
for(int k=0; k<g[b].size(); k++) g[a].push_back(g[b][k]);//这个地方是把刚加进来的点加入当前树的点集中
f[b]=a;//一定注意这个地方和前面是关联的,不能f[a]=b
p[i].vis=1;
MST+=p[i].cost;
}
}
int ans=INF;
for(int i=1; i<=m; i++)//枚举除了最小生成树剩下的边,把它放进最小生成树会形成环,然后去掉当前环里面的最大的边,然后找出这些生成树里面最小的,就是次小的
if(!p[i].vis)
ans=min(ans,MST+p[i].cost-dis[p[i].x][p[i].y]);
if(ans==MST) printf("Not Unique!\n");//这题是严格的次小,即权值相等就是不唯一,还有不严格的次小,权值只有大于最小生成树才是次小生成树
else printf("%d\n",MST);
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(int i=1; i<=m; i++)
{
scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].cost);
p[i].vis=0;
}
kruskal();
}
return 0;
}