题目链接:
题意:
给出 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