POJ 3522
//题目大意:求一棵生成树让最大边最小边差值最小
//题目类型:最小生成树+枚举
//解题思路:分析可知生成树一定是最小生成树,利用Kruskal算法枚举所有的最小生成树
#include <iostream>
#include <algorithm>
//#include <conio.h>
using namespace std;
#define narray 101
#define marray 5000
const int INF = 0x7fffffff;
typedef struct edge
{
int a;
int b;
int w;
}edge;
edge edges[marray];
int final[narray];
int cnt[narray];
int n,m;
bool cmp(const edge a,const edge b)
{
return a.w<b.w;
}
int findp(int n)
{
if(final[n]==n)
return n;
else
final[n]=findp(final[n]);
return final[n];
}
bool Union(int a,int b)
{
int roota = findp(a);
int rootb = findp(b);
if(roota!=rootb)
{
if(cnt[a]>=cnt[b])
{
final[rootb] = roota;
cnt[roota]+=cnt[rootb];
}
else
{
final[roota] = rootb;
cnt[rootb]+=cnt[roota];
}
return true;
}
else
return false;
}
int main()
{
//freopen("1.txt","r",stdin);
int a,b,w;
int i,j;
int num;
int minslim;
int firstw,lastw;
while(scanf("%d%d",&n,&m)!=-1)
{
if(n==0 && m==0) break;
minslim = INF;
for(i=1;i<=m;++i)
{
scanf("%d%d%d",&edges[i].a,&edges[i].b,&edges[i].w);
}
sort(edges+1,edges+m+1,cmp);
bool flag = false;
if(n==2 && m==1) //注意考虑只有两个顶点一条边的情况
{
printf("0\n");
continue;
}
for(j=1;j<=m;++j) //枚举
{
num = 0;
for(i=1;i<=n;++i)
{
final[i] = i;
cnt[i] = 1;
}
for(i=j;i<=m;++i)
{
if(j+n-2>m) //剪枝
{
flag = true;
break;
}
a = edges[i].a;
b = edges[i].b;
w = edges[i].w;
if(Union(a,b))
{
num++;
if(num==1)
firstw = w;
else if(num==n-1)
{
lastw = w;
if(lastw-firstw<minslim)
minslim = lastw-firstw;
break;
}
}
}
if(flag)
break;
}
if(minslim == INF) printf("-1\n");
else printf("%d\n",minslim);
}
//getch();
return 0;
}