题目链接
题意
问最小生成树是否唯一
思路
求取次小生成树,看是否和最小生成树权值一样即可
总的来说是道模板题,在写之前没学次小生成树,想的是一种朴素做法
枚举每一条最小生成树的边,去掉后重新求最小生成树,比较权值即可。但 是缺点很明显,复杂度大,每次删除还要判断图是否联通。
之后学习了一下次小生成树的算法,大概思想就是枚举不在最小生成树的边,加入最小生成树后一定会形成环路,删除掉环路中最大的边,比较答案即可。
代码
#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<string>
#include<queue>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<vector>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
//#define int long long
using namespace std;
typedef long long ll;
const int maxn=80000;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;
int fa[maxn];
vector<int>G[150];
int dis[150][150];
struct Edge{
int u,v;
int w;
int mbl;
}edge[maxn];
void init(int n){
for(int i=0;i<=n;i++){
G[i].clear();
G[i].push_back(i);
fa[i]=i;
}
}
int find(int x){
return x==fa[x]?x:fa[x]=find(fa[x]);
}
void unite(int x,int y){
int fx=find(x),fy=find(y);
if(fx==fy)
return ;
fa[fx]=fy;
int len=G[fx].size();
for(int i=0;i<len;i++)
G[fy].push_back(G[fx][i]);
return ;
}
bool cmp(Edge a,Edge b){
return a.w<b.w;
}
int main(){
IOS
int tn;
bool bl;
cin>>tn;
while(tn--){
memset(edge,0,sizeof edge);
int n,m;
cin>>n>>m;
init(n);
for(int i=1;i<=m;i++)
cin>>edge[i].u>>edge[i].v>>edge[i].w;
int ans=0;
sort(edge+1,edge+1+m,cmp);
for(int i=1;i<=m;i++){
int u=edge[i].u,v=edge[i].v;
int fu=find(u),fv=find(v);
if(fu!=fv){
edge[i].mbl=1;
ans+=edge[i].w;
int len1=G[fu].size(),len2=G[fv].size();
for(int ii=0;ii<len1;ii++)
for(int j=0;j<len2;j++)
dis[G[fu][ii]][G[fv][j]]=dis[G[fv][j]][G[fu][ii]]=edge[i].w;
unite(u,v);
}
}
int t=inf;
for(int i=1;i<=m;i++){
if(edge[i].mbl)
continue;
t=min(t,ans+edge[i].w-dis[edge[i].u][edge[i].v]);
}
if(t>ans)
cout<<ans<<endl;
else
cout<<"Not Unique!"<<endl;
}
return 0;
}