您的位置:首页 > 产品设计 > UI/UE

poj 1679 The Unique MST(次小生成树)

2013-07-07 22:31 399 查看
[align=center]TheUniqueMST[/align]

TimeLimit:1000MSMemoryLimit:10000K
TotalSubmissions:17061Accepted:5919
Description
Givenaconnectedundirectedgraph,tellifitsminimumspanningtreeisunique.

Definition1(SpanningTree):Consideraconnected,undirectedgraphG=(V,E).AspanningtreeofGisasubgraphofG,sayT=(V',E'),withthefollowingproperties:

1.V'=V.

2.Tisconnectedandacyclic.

Definition2(MinimumSpanningTree):Consideranedge-weighted,connected,undirectedgraphG=(V,E).TheminimumspanningtreeT=(V,E')ofGisthespanningtreethathasthesmallesttotalcost.ThetotalcostofTmeansthesumoftheweightsonall
theedgesinE'.

Input
Thefirstlinecontainsasingleintegert(1<=t<=20),thenumberoftestcases.Eachcaserepresentsagraph.Itbeginswithalinecontainingtwointegersnandm(1<=n<=100),thenumberofnodesandedges.Eachofthe
followingmlinescontainsatriple(xi,yi,wi),indicatingthatxiandyiareconnectedbyanedgewithweight=wi.Foranytwonodes,thereisatmostoneedgeconnectingthem.
Output
Foreachinput,iftheMSTisunique,printthetotalcostofit,orotherwiseprintthestring'NotUnique!'.
SampleInput
2
33
121
232
313
44
122
232
342
412

SampleOutput
3
NotUnique!

题意:给出一个无向图,求最小生成树是否唯一。

思路:法一:次小生成树的边不会和最小生成树完全相同,因此可以先求一次最小生成树,然后枚举去掉最小生成树中的任意一条边(需要枚举n-1次),每次在剩下的边里用kruskal算法求一次最小生成树。这n-1棵最小生成树中权值最小的即为原图的次小生成树。时间复杂度为O(NElogE),稠密图时接近O(n^3)。这种方法虽简易直观,但是效率较低。法二:首先用prim算法求出原图的最小生成树,记录权值之和为MST。枚举添加每条不在最小生成树上的边(u,v)到最小生成树上,加上以后一定会形成一个环。找到环上权值第二大的边(即除了(u,v)以外的权值最大的边),把它删掉,计算当前生成树的权值之和。取所有枚举修改的生成树权值之和的最小值,就是次小生成树加入一条边时,如何找到环上权值第二大的边呢?定义path[u][v]为从u到v的路径上最大边的权值,path[u][v]的值可在求原图最小生成树时得出。然后对于添加每条不在最小生成树中的边(u,v),新的生成树权值之和就是MST+G[u][v]–path[u][v],其最小值则为次小生成树。

注意此题存在图不连通的状况。


AC代码:法一:

#include<cstring>
#include<string>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>
#include<vector>
#include<cstdlib>
#include<iostream>
#definemax2(a,b)((a)>(b)?(a):(b))
#definemin2(a,b)((a)<(b)?(a):(b))

usingnamespacestd;
constintINF=100000000;
structnode
{
intu,v,w;
}edge[5000];
intfa[105];
intmintree[105];
intn,m,top;
intcmp(nodea,nodeb)
{
returna.w<b.w;
}
voidinit()
{
for(inti=1;i<=n;i++)
fa[i]=i;
}
intFind_set(intx)
{
if(x==fa[x])returnx;
fa[x]=Find_set(fa[x]);
returnfa[x];
}
intKruskal(intdele)
{
init();
intcnt=0,sum=0;
for(inti=0;i<m;i++)
{
if(cnt==n-1)break;
if(i==dele)continue;
intx=Find_set(edge[i].u);
inty=Find_set(edge[i].v);
if(x==y)continue;
fa[x]=y;
sum+=edge[i].w;
if(dele==-1)
mintree[top++]=i;
cnt++;
}
returnsum;
}
intmain()
{
intt;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(inti=0;i<m;i++)
scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
sort(edge,edge+m,cmp);
top=0;
intMST=Kruskal(-1);
intccs=0;
for(inti=1;i<=n;i++)//判断图是否连通
{
if(fa[i]==i)ccs++;
}
if(ccs>1)
{
printf("0\n");
continue;
}
inttemp;
boolunique=true;
for(inti=0;i<top;i++)
{
temp=Kruskal(mintree[i]);//删除最小生成树第i条边,再求一次最小生成树
ccs=0;
for(inti=1;i<=n;i++)
{
if(fa[i]==i)ccs++;
}
if(ccs>1)continue;
if(temp==MST)
{
unique=false;
break;
}
}
if(unique)printf("%d\n",MST);
else
printf("NotUnique!\n");
}
return0;
}


法二:

#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cstdio>
#include<cmath>
#defineL(rt)(rt<<1)
#defineR(rt)(rt<<1|1)
usingnamespacestd;

constintINF=100000000;
constintmaxn=105;
intG[maxn][maxn];
intdis[maxn],path[maxn][maxn],pre[maxn];
boolvis[maxn],used[maxn][maxn];
intn;
voidprim()
{
intx,m,sum=0;
memset(vis,false,sizeof(vis));
memset(path,0,sizeof(path));
for(inti=1;i<=n;i++)
{
dis[i]=G[1][i];
pre[i]=1;
}
vis[1]=true;
for(inti=1;i<n;i++)
{
m=INF;
for(intj=1;j<=n;j++)
if(!vis[j]&&dis[j]<m)
m=dis[x=j];
if(m==INF)break;
sum+=m;
vis[x]=true;
used[pre[x]][x]=used[x][pre[x]]=false;
for(intj=1;j<=n;j++)
{
if(vis[j]&&j!=x)
path[x][j]=path[j][x]=max(path[pre[x]][j],m);
if(!vis[j]&&G[x][j]<dis[j])
{
dis[j]=G[x][j];
pre[j]=x;
}
}
}
m=INF;
for(inti=1;i<=n;i++)
for(intj=1;j<=n;j++)
if(used[i][j]&&i!=j)
m=min(m,sum-path[i][j]+G[i][j]);
if(m==sum)
printf("NotUnique!\n");
else
printf("%d\n",sum);
}
intmain()
{
intt,m,u,v,w;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(inti=1;i<=n;i++)
for(intj=1;j<=n;j++)
{
if(i==j)G[i][j]=0;
else
G[i][j]=G[j][i]=INF;
}
while(m--)
{
scanf("%d%d%d",&u,&v,&w);
G[u][v]=G[v][u]=w;
used[u][v]=used[v][u]=true;
}
prim();
}
return0;
}



                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: