题目大意是:给定一个带权无向图,求该图的所有生成树(并不是最小生成树)中的最小的最大权值与最小权值之差。
解析:要求所有生成树中的最小的最大权值与最小权值之差,当然不能一个一个求出来进行比较,仔细分析就可以知道,只需将图的所有边按权值大小升序排序,依次枚举每一条边,以每一条边的权值为下限求最小生成树,因为生成最小生成树时,每次都是取可以取的权值最小的边来构成最小生成树,因而保证了以该边为权值下限求出的最小生成树的最大权值与最小权值之差是以该边权值为下限生成的所有的生成树的最大权值与最小权值之差的最小值,枚举完所有要枚举的边就可以求出该图的最小的最大权值与最小权值之差。
代码如下,时间用了94ms,还算快。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;
const int maxn=102;
const int maxm=maxn*(maxn-1)/2;
int n,m,bin[maxn];
struct Edge
{
int u;
int v;
int w;
}edge[maxm];
int cmp(const void *a,const void *b)
{
Edge *p=(Edge *)a,*q=(Edge *)b;
return p->w-q->w;
}
int find(int x)
{
int r;
r=x;
while(r!=bin[r])
r=bin[r];
return r;
}
int Kruskal(int a) //以下标为v(V边的权值最小)的边生成最小生成树
{
int i,j,k,u,v;
i=a;
j=n; //顶点个数
for(k=1;k<=n;k++)
bin[k]=k;
while(i<m && j>1) //每生成最小生成树的一条边要消耗两个顶点,所以是j>1
{
u=find(edge[i].u);
v=find(edge[i].v);
if(u!=v)
{
bin[u]=v;
j--;
}
i++;
}
if(j>1) //还有顶点没有参与构成最小生成树,说明不存在最小生成树
return -1;
return edge[i-1].w-edge[a].w; //返回最小生成树的最大权值和最小权值之差
}
int main()
{
int i,ans,temp;
while(scanf("%d%d",&n,&m))
{
if(n==0 && m==0)
break;
for(i=0;i<m;i++)
scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
qsort(edge,m,sizeof(edge[0]),cmp);
ans=Kruskal(0); //先计算原图是否有最小生成树,若没有,则不必进行后面的计算
if(ans==-1)
{
printf("-1\n");
continue;
}
for(i=1;i<m;i++)
{
if(edge[i].w==edge[i-1].w)
continue; //相同下限权值的边只需考虑一次
temp=Kruskal(i);
if(temp==-1) //无法构成最小生成树,无需进行后续的考察
break;
ans=min(ans,temp);
}
printf("%d\n",ans);
}
return 0;
}