题目链接:
题意:
给出 M个点N条边 求它的的最小生成树 不唯一则输出:Not Unique!
题解:
prim:判断“最小生成树是否唯一”可以理解为“最小生成树和次小生成树是否相等”
求次小生成树的步骤如下
1)先求出最小生成树T,在prim的同时,用一个矩阵maxx[u][v]记录在树中连接u-v的路径中权值最大的边.
2)枚举所有不在T中的边map[u][v],加入边u-v,删除权值为maxx[u][v]的边;
3)找到MST-maxx[u][v]+map[u][v]的最小值即为次小生成树的值,而如果
maxx[u][v]==map[u][v] 则说明最小生成树和次小生成树相等.
kurskal:
通过kurskal算法标记最小生成树中的每条边 used=1, 然后每次删除一条(标记used==1且权值与其他边的相同的边)
再进行kruskal算法 如果求得的值==MST 则说明MST不唯一
prim代码:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; #define max1 0x3f3f3f3f int lowdis[105]; int map[105][105]; int connect[105][105]; //标记所有不在生成树的边 int maxx[105][105]; //保存 u->v 的最大边 int pre[105]; int m,ans; void prim() { int i,j,pree,loc,minn; for(i=1; i<=m; i++) { lowdis[i]=map[1][i]; pre[i]=1; } lowdis[1]=-1; for(i=1; i<m; i++) { minn=max1; for(j=1; j<=m; j++) if(lowdis[j]!=-1&&lowdis[j]<minn) minn=lowdis[j],loc=j; ans+=lowdis[loc]; pree=pre[loc]; connect[pree][loc]=connect[loc][pree]=0; maxx[pree][loc]=lowdis[loc]; // for(j=1; j<=m; j++) maxx[j][loc]=maxx[j][pree]>maxx[pree][loc]?maxx[j][pree]:maxx[pree][loc]; lowdis[loc]=-1; for(j=1; j<=m; j++) if(lowdis[j]>map[loc][j]) lowdis[j]=map[loc][j],pre[j]=loc; } return; } int main() { int t,i,j,a,b,c,n; scanf("%d",&t); while(t--) { ans=0; scanf("%d%d",&m,&n); memset(connect,0,sizeof(connect)); memset(map,max1,sizeof(map)); memset(maxx,0,sizeof(maxx)); while(n--) { scanf("%d%d%d",&a,&b,&c); map[a][b]=map[b][a]=c; connect[a][b]=connect[b][a]=1; } prim(); int t=0; for(i=1; i<=m; i++) { for(j=1; j<=m; j++) //枚举每一条不在生成树中的边 { if(map[i][j]==max1||connect[i][j]==0) continue; if(map[i][j]==maxx[i][j]) //如果要求次小生成树 min(ans+map[i][j]-maxx[i][j])即可 { t=1; cout<<"Not Unique!"<<endl; break; } } if(t==1) break; } if(t==0) cout<<ans<<endl; } return 0; }
Kruskal代码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; struct node { int u,v,w; int delate,used,equall; } edge[10005]; int fa[10005],m,s,flag; int cmp(node a,node b) { return a.w<b.w; } int find(int x) { int t,d=x; while(fa[d]>=0) d=fa[d]; while(x!=d) { t=fa[x]; fa[x]=d; x=t; } return d; } int kruskal() { memset(fa,-1,sizeof(fa)); int ans=0,r1,r2,ss,nn=0,i; for(i=0; i<s; i++) { r1=find(edge[i].u); r2=find(edge[i].v); if(r1!=r2&&edge[i].delate==0) { if(!flag) edge[i].used=1; ss=fa[r1]+fa[r2]; nn++; ans+=edge[i].w; if(fa[r1]<fa[r2]) fa[r1]=ss,fa[r2]=r1; else fa[r1]=r2,fa[r2]=ss; } if(nn==m-1) return ans; } return 0; } int main() { int t,i,j,n; int a,b,c; int ans1,ans2; scanf("%d",&t); while(t--) { flag=s=0; scanf("%d%d",&m,&n); while(n--) { scanf("%d%d%d",&a,&b,&c); edge[s].delate=edge[s].equall=edge[s].used=0; edge[s].u=a; edge[s].v=b; edge[s++].w=c; } for(i=0; i<s; i++) for(j=0; j<i; j++) { if(edge[i].w==edge[j].w) edge[i].equall=edge[j].equall=1; } sort(edge,edge+s,cmp); ans1=kruskal(); flag=1; a=0; for(i=0; i<s; i++) { if(edge[i].equall==1&&edge[i].used==1) { edge[i].delate=1; ans2=kruskal(); if(ans1==ans2&&ans1!=0) { a=1; cout<<"Not Unique!"<<endl; break; } edge[i].delate=0; } } if(a==0) cout<<ans1<<endl; } return 0; }
POJ 1679 The Unique MST 判断最小生成树是否唯一/次小生成树
原文地址:http://blog.csdn.net/axuan_k/article/details/43149989