通常次小生成树是使用Prim算法进行实现的,因为可以在Prim算法松弛的同时求得最小生成树上任意两点之间的最长边。但是利用Kruskal算法却没办法在松弛的同时求得。
所以我们就要在Kruskal求完最短路后,对于每个顶点bfs一次,得到树上任意两点的最长边。之后求可以像之前一样枚举不在树上的边,代替找最小值了。
两种方法的时间杂度是一样的,但Kruskal的实现代码回长非常多,不过Kruskal的实现可以处理Prim难以处理的重边。
代码实现以Uva 10462为例:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
using namespace std;
#define INF 0x3f3f3f3f
#define fi first
#define se second
#define mem(a,b) memset((a),(b),sizeof(a))
const int MAXV=100+3;
const int MAXE=200+3;
struct Edge
{
int from,to,cost;
Edge(int f=0,int t=0,int c=0):from(f),to(t),cost(c){}
bool operator<(const Edge &other)const
{
return cost<other.cost;
}
}edge[MAXE];
int V,E,par[MAXV],high[MAXV],the_max[MAXV][MAXV];
bool used[MAXE];//边是否使用的标记
bool vis[MAXV];
vector<pair<int,int> > G[MAXV];//最小生成树
void init()//初始化
{
for(int i=1;i<=E;++i)
used[i]=false;
for(int i=1;i<=V;++i)
{
par[i]=i;
high[i]=0;
G[i].clear();
}
}
int findfather(int x)
{
return par[x]=par[x]==x?x:findfather(par[x]);
}
bool unite(int a,int b)
{
int fa=findfather(a),fb=findfather(b);
if(fa==fb)
return false;
if(high[fa]>high[fb])
par[fb]=fa;
else
{
par[fa]=fb;
if(high[fa]==high[fb])
++high[fb];
}
return true;
}
void bfs(int s)
{
mem(vis,0);
vis[s]=true;
the_max[s][s]=0;
queue<int> que;
que.push(s);
while(!que.empty())
{
int u=que.front(); que.pop();
for(int i=0;i<G[u].size();++i)
{
int v=G[u][i].fi;
if(!vis[v])
{
vis[v]=true;
the_max[s][v]=max(the_max[s][u],G[u][i].se);
que.push(v);
}
}
}
}
int main()
{
int T_T;
scanf("%d",&T_T);
for(int cas=1;cas<=T_T;++cas)
{
printf("Case #%d : ",cas);
scanf("%d%d",&V,&E);
init();
for(int i=0;i<E;++i)
scanf("%d%d%d",&edge[i].from,&edge[i].to,&edge[i].cost);
sort(edge,edge+E);
int res=0;
for(int i=0;i<E;++i)
if(unite(edge[i].from,edge[i].to))
{
res+=edge[i].cost;
used[i]=true;
G[edge[i].from].push_back(make_pair(edge[i].to,edge[i].cost));
G[edge[i].to].push_back(make_pair(edge[i].from,edge[i].cost));
}
bool ok=true;
for(int i=2;i<=V;++i)
if(findfather(i)!=findfather(1))
{
ok=false;
break;
}
if(!ok)//不联通
{
puts("No way");
continue;
}
if(E==V-1)//生成树唯一
{
puts("No second way");
continue;
}
for(int i=1;i<=V;++i)
bfs(i);
int ans=INF;
for(int i=0;i<E;++i)
if(!used[i])
ans=min(ans,res-the_max[edge[i].from][edge[i].to]+edge[i].cost);
printf("%d\n",ans);
}
return 0;
}