题意:给定N和M,表示N个顶点和M条边,问最小生成树是否唯一。
思路:求次小生成树,判断是否和最小生成树一样。
参考http://blog.youkuaiyun.com/sunbaigui/archive/2009/10/11/4653271.aspx
以前prim的主循环都做了N次,这次严谨点,只做N-1次!
主要理解:for(j=1;j<=n;j++) { maxlen[pre[k]][k]=maxlen[k][pre[k]]=g[pre[k]][k]; if(vis[j]==false) { maxlen[j][k]=maxlen[k][j]=maxlen[j][k]>maxlen[pre[k]][k]?maxlen[j][k]:maxlen[pre[k]][k]; } }
#include<iostream> #include<cstdio> #include<cstring> #define maxcost 999999999 using namespace std; int n,m; int g[110][110],dist[110],vis[110],maxlen[110][110],pre[110]; int prim() { int min,dis,i,j,k; int ans=0; for(i=1;i<=n;i++) for(j=1;j<=n;j++) maxlen[i][j]=-maxcost; for(i=1;i<=n;i++) { pre[i]=1; dist[i]=g[1][i]; vis[i]=true; } vis[1]=false;dist[1]=0; for(i=1;i<n;i++) { min=maxcost;k=1; for(j=1;j<=n;j++) if(vis[j]&&dist[j]<min) { min=dist[j];k=j; } vis[k]=false; ans+=min; for(j=1;j<=n;j++) { maxlen[pre[k]][k]=maxlen[k][pre[k]]=g[pre[k]][k]; if(vis[j]==false) { maxlen[j][k]=maxlen[k][j]=maxlen[j][k]>maxlen[pre[k]][k]?maxlen[j][k]:maxlen[pre[k]][k]; } } for(j=1;j<=n;j++) if(vis[j]&&dist[j]>g[k][j]) { dist[j]=g[k][j]; pre[j]=k; } } for(i=1;i<=n;i++) for(j=1+1;j<=n;j++) { if(pre[i]==j||pre[j]==i)//已用 {} else if(maxlen[i][j]==g[i][j]) return -1; } return ans; } int main() { int t,x,y,dis; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) g[i][j]=maxcost; while(m--) { scanf("%d%d%d",&x,&y,&dis); g[x][y]=g[y][x]=dis; } int k=prim(); if(k==-1) printf("Not Unique!\n"); else printf("%d\n",k); } return 0; }