Description
给出n个点 (n≤100) ,m条边,求出最大边减最小边差值最小的生成树。
Solution
首先可以注意到n不是很大,最大只有100,自然而然想到的就是暴力的做法。
将边按权值从小到大排序。在排好序的边中枚举[L,R]区间内的边,判断是否能形成最小生成树,若可以,则当前的差值就为 e[R].w−e[L].w 。
可以注意到,对于枚举R的范围内,已经是最优的,因为当R继续增大时,对应权值也会增大,此时结果不会最优。所以可以跳出循环。但是并不意味着是全局最优的,因此还需要继续枚举L。
Code
#include<bits/stdc++.h>
#define ll long long
#define nmax 10000+5
#define nume 105
using namespace std;
struct edg{
int f,t,w;
}e[nmax];
int fa[nume];
int n,m,ans = 100000000;
void makeset(int x){
fa[x] = x;
}
int findset(int x){
int rt = x, temp;
while(fa[rt] != rt) rt=fa[rt];
while(x!=rt){
temp = fa[x];
fa[x] = rt;
x = temp;
}
return rt;
}
int unionset(int x ,int y){
x = findset(x);
y = findset(y);
if(x == y) return -1;
else{
fa[x] = y;
return 0;
}
}
bool cmp(edg a, edg b){
if(a.w<b.w) return true;
else if(a.w == b.w){
return a.f < b.f;
}else return false;
}
void kur(){
int num = n;
int sta = 0,ed = 0;
for(int i = 0;i<m;++i){
for(int j = i;j<m;++j){
num = n;
sta = e[i].w,ed=e[j].w;
for(int k = i;k<=j;++k){
if(unionset(e[k].f,e[k].t)!=-1){
num--;
}
}
for(int i = 1;i<=n;++i) makeset(i);
if(num == 1){
ans = min(ed - sta,ans);
break;
}
}
}
}
int main(){
while(scanf("%d %d",&n,&m) != EOF){
if(n == 0 && m == 0) break;
ans = 100000000;
for(int i = 1;i<=n;++i) makeset(i);
for(int i = 0;i<m;++i){
scanf("%d %d %d",&e[i].f,&e[i].t,&e[i].w);
}
sort(e,e+m,cmp);
kur();
if(ans == 100000000) printf("-1\n");
else printf("%d\n",ans);
}
return 0;
}