题意:有n个点,m个遍的无向图,问是否存在唯一最小生成树,存在则输出最小生成树边权和。否则输出Not Unique!
思路:当然首先判断是否构成生成树,然后用次小生成树和最小生成树比较,如果相等则就不唯一了。否则唯一。
(这里说的次小生成树是非严格的次小生成树 Σw次≥Σw最小)
代码:
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #define inf 0x3f3f3f3f using namespace std; typedef long long ll; using namespace std; const int maxn=110; bool visit[maxn]; int Map[maxn][maxn]; bool used[maxn][maxn];//两个点的那条边是否被使用过; int Max[maxn][maxn];//记录MST中两个点的最大距离; int dist[maxn]; int pre[maxn];//保存父节点; int n,m,ans; int prime()//求最小生成树 { ans=0; memset(visit,false,sizeof(visit)); memset(Max,0,sizeof(Max)); memset(used,0,sizeof(used)); visit[1]=1; pre[1]=-1; for(int i=2;i<=n;i++) { dist[i]=Map[1][i]; pre[i]=1; } dist[1]=0; for(int i=1;i<=n-1;i++) { int lowcast=inf; int temp=-1; for(int j=1;j<=n;j++) { if(!visit[j]&&lowcast>dist[j]) { lowcast=dist[j]; temp=j; } } if(lowcast==inf)//这说明有点不连通; return -1; ans+=lowcast;//最小生成树的值; visit[temp]=1; used[temp][pre[temp]]=used[pre[temp]][temp]=1; for(int j=1;j<=n;j++) { if(visit[j]) Max[j][temp]=Max[temp][j]=max(Max[j][pre[temp]],dist[temp]);//数组的作用是记录MST里面两个点的最大距离; if(!visit[j]&&dist[j]>Map[temp][j]) { dist[j]=Map[temp][j]; pre[j]=temp; } } } return ans; } int SMST() { int minn=inf; for(int i=1;i<=n;i++) { for(int j=i+1;j<=n;j++) { if(Map[i][j]!=inf&&(!used[i][j])) { minn=min(minn,ans+Map[i][j]-Max[i][j]); } } } if(minn==inf) return -1;//没有次小生成树; return minn; } int main() { int t; int x,y,w; cin>>t; while(t--) { cin>>n>>m; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(i==j) Map[i][j]=0; else Map[i][j]=inf; for(int i=1;i<=m;i++) { cin>>x>>y>>w; Map[x][y]=Map[y][x]=w; } int ans=prime(); if(ans==-1) { printf("Not Unique! "); continue; } if(ans==SMST()) printf("Not Unique! ");//最小生成树和次小生成树相等 else printf("%d ",ans); } return 0; }