您的位置:首页 > 其它

Uva 10600 ACM Contest and Blackout(次小生成树)

2016-04-17 15:06 344 查看
题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1541

题意:求一个图的最小生成树和次小生成树。

题解:

/*

*算法引入:

*设G=(V,E,w)是连通的无向图,T是图G的一棵最小生成树;

*如果有另一棵树T1,满足不存在树T’,ω(T’)<ω(T1),则称T1是图G的次小生成树;

*

*算法思想:

*邻集的概念:由T进行一次可行交换得到的新的生成树所组成的集合,称为树T的邻集,记为N(T);

*设T是图G的最小生成树,如果T1满足ω(T1)=min{ω(T’)|T’∈N(T)},则T1是G的次小生成树;

*首先先求该图的最小生成树T,时间复杂度O(Vlog2V+E);

*然后,求T的邻集中权值和最小的生成树,即图G 的次小生成树;

*如果只是简单的枚举,复杂度很高;

*首先枚举两条边的复杂度是O(VE),再判断该交换是否可行的复杂度是O(V),则总的时间复杂度是O(V2E);

*分析可知,每加入一条不在树上的边,总能形成一个环,只有删去环上的一条边,才能保证交换后仍然是生成树;

*而删去边的权值越大,新得到的生成树的权值和越小,可以以此将复杂度降为O(VE);

*更好的方法:首先做一步预处理,求出树上每两个结点之间的路径上的权值最大的边;

*然后枚举图中不在树上的边,有了预处理,就可以用O(1)的时间得到形成的环上的权值最大的边;

*预处理:因为是一棵树,只要简单的BFS即可,预处理所要的时间复杂度为O(V2);

* /

引用自:/article/8171700.html

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int VMAX=100+5;
const int EMAX=VMAX*VMAX;
const int INF=0x3f3f3f3f;
int g[VMAX][VMAX],maxd[VMAX][VMAX];//g---存图,maxd存树上两点之间路径的最大权
int vis[VMAX];
int dist[VMAX];
int pre[VMAX];//前驱
int use[VMAX][VMAX];//0表示没用过,1表示用过,2表示不存在
int n,m;
int firmst,secmst;
int prim()
{
memset(maxd,0,sizeof(maxd));
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
{
dist[i]=g[1][i];
pre[i]=1;
}
firmst=0;
vis[1]=1;
for(int i=1;i<n;i++)
{
int p=-1,mmin=INF;
for(int j=1;j<=n;j++)
{
if(!vis[j]&&mmin>dist[j])
{
mmin=dist[j];
p=j;
}
}
if(p!=-1)
{
use[pre[p]][p]=use[p][pre[p]]=1;
for(int j=1;j<=n;j++)
{
if(vis[j])
{
maxd[j][p]=max(maxd[j][pre[p]],g[pre[p]][p]);
}
}
vis[p]=1;
firmst+=mmin;
for(int j=1;j<=n;j++)
{
if(!vis[j]&&dist[j]>g[p][j])
{
dist[j]=g[p][j];
pre[j]=p;
}
}
}
}
return firmst;
}
int secMst()
{
int mmin=INF;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(use[i][j]==0)
mmin=min(mmin,g[i][j]-maxd[i][j]);
}
}
return secmst=firmst+mmin;
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int T;
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]=INF;
use[i][j]=2;
}
}
while(m--)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
g[a][b]=c;
g[b][a]=c;
use[a][b]=0;
use[b][a]=0;
}
prim();
secMst();
printf("%d %d\n",firmst,secmst);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: