题目大意:给定一个无向连通图,回答它的最小生成树是否是唯一的。
思路:先求出这个图的最小生成树,然后枚举每条不在最小生成树上的边(u,v)。由于这条边(u,v)与最小生成树上连接u和v两点的链构成了一个环,因此可以通过倍增LCA找到链上最小的边,在答案中删除之并加上枚举的边(u,v),判断与之前最小生成树是否相等即可。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=100+100,M=10000+100; int n,m; struct node{ int to,nxt,w; }e[M]; int head[N],tot; void add(int u,int v,int w) { e[++tot]=(node){v,head[u],w}; head[u]=tot; } int fa[N]; int find(int u) { return fa[u]==u?u:fa[u]=find(fa[u]); } struct ed { int u,v,w; }E[M]; bool cmp(ed a,ed b) { return a.w<b.w; } int mst; bool yes[M]; void kruskal() { int cnt=0; mst=0; sort(E+1,E+m+1,cmp); for(int i=1;i<=n;i++) fa[i]=i; for(int i=1;i<=m;i++) { int u=E[i].u,v=E[i].v,w=E[i].w; int f1=find(u),f2=find(v); if(f1!=f2) { mst+=w; yes[i]=true; if(rand()%2) fa[f1]=f2; else fa[f2]=f1; cnt++; if(cnt==n-1) return ; } } } int dep[N],dad[N],f[N][25][3]; void dfs(int u) { for(int i=head[u];i;i=e[i].nxt) { int v=e[i].to; if(!dep[v]) { dep[v]=dep[u]+1; f[v][0][0]=u; f[v][0][1]=e[i].w; dad[v]=u; dfs(v); } } } void pre() { for(int i=1;i<=20;i++) { for(int j=1;j<=n;j++) { f[j][i][0]=f[f[j][i-1][0]][i-1][0]; f[j][i][1]=max(f[j][i-1][1],f[f[j][i-1][0]][i-1][1]); } } } int query(int u,int v) { int ans=-(1<<30); if(dep[u]<dep[v]) swap(u,v); for(int i=20;i;i--) { if(dep[f[u][i][0]]>=dep[v]) { ans=max(ans,f[u][i][1]); u=f[u][i][0]; } } if(u==v) return ans; for(int i=20;i;i--) { if(f[u][i][0]!=f[v][i][0]) { ans=max(ans,max(f[u][i][1],f[v][i][1])); u=f[u][i][0]; v=f[v][i][0]; } } ans=max(ans,max(f[u][0][1],f[v][0][1])); return ans; } void solve() { int ans=(1<<30); for(int i=1;i<=n;i++) { if(!dep[i]) { dad[i]=i; dep[i]=1; dfs(i); } } pre(); for(int i=1;i<=m;i++) { int u=E[i].u,v=E[i].v,w=E[i].w; if(!yes[i]) ans=min(ans,mst-query(u,v)+w); } if(ans==mst) printf("Not Unique!\n"); else printf("%d\n",mst); } int main() { int t; scanf("%d",&t); while(t--) { tot=0; memset(e,0,sizeof(e)); memset(head,0,sizeof(head)); memset(yes,0,sizeof(yes)); memset(dep,0,sizeof(dep)); memset(f,0,sizeof(f)); memset(E,0,sizeof(E)); scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); E[i]=(ed){u,v,w}; add(u,v,w); } kruskal(); solve(); } return 0; }