题目大意:
给你$n$个点和$m$条边,要求你输出最小生成树的边权之和并判断最小生成树是否唯一.
solution:
最小生成树板子,Kruskal即可.至于判断唯一性,这里有一种耐人寻味的解法.对于每一个边权值$z$,我们可以寻找所有边权与其相等的边并统计其中合法边数sum,然后再扫描一次选其中足够的合法边并加入最小生成树,如果有剩余的合法边,则说明可以替换,即最小生成树不唯一.
code:
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #define R register #define next exnt #define debug puts("mlg") using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; inline ll read(); inline void writesp(ll x); inline void writeln(ll x); inline void write(ll x); ll T; ll n,m; struct node{ ll X,Y,Z; }t[220000]; inline bool cmp(node x,node y){ return x.Z<y.Z; } ll f[220000]; inline void init(){ for(R ll i=1;i<=n;i++) f[i]=i; } inline ll getf(ll x){ return f[x]==x?x:f[x]=getf(f[x]); } inline bool check(ll x,ll y){ return getf(x)==getf(y); } inline void merge(ll x,ll y){ f[getf(y)]=getf(x); } ll sum,total,ans; int main(){ T=read(); while(T--){ n=read(),m=read(); init(); for(R ll i=1;i<=m;i++) t[i].X=read(),t[i].Y=read(),t[i].Z=read(); sort(t+1,t+m+1,cmp); total=ans=sum=0; for(R ll i=1;i<=m;i++){ for(R ll j=i;j<=m&&t[j].Z==t[i].Z;j++){ if(!check(t[j].X,t[j].Y)){ ++sum; } } do{ if(!check(t[i].X,t[i].Y)){ merge(t[i].X,t[i].Y); ans+=t[i].Z; ++total; } if(total==n-1) break; ++i; }while(t[i].Z==t[i-1].Z&&i<=m); if(total==n-1) break; --i; } writeln(ans); if(sum>n-1) puts("No"); else puts("Yes"); } } inline ll read(){ ll x=0,t=1;char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') t=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ x=x*10+ch-'0'; ch=getchar(); } return x*t; } inline void write(ll x){ if(x<0){putchar('-');x=-x;} if(x<=9){putchar(x+'0');return;} write(x/10);putchar(x%10+'0'); } inline void writesp(ll x){ write(x);putchar(' '); } inline void writeln(ll x){ write(x);putchar(' '); }
感谢机房神犇zxt提供思路