这道题也是今天模拟赛的一道题,竟在poj上找到了,虽然有一丝差别。
题意:给一个图,求所有生成树中,最大边和最小边差值的最小值。
多组输入,可能会有不连通的情况,就是一丝差别。。。
/*
感觉自己也是NC,最开始的做法竟然是二分,判定答案mid是否可行的方法就是以beg为第一条边(最小或最大皆可,这篇博客里是以最小为例,就是说kruskal跑的是最小生成树),(1<=beg<=m-n+2)生成所有的最小生成树,一旦有边长与beg长的差超过mid就停止,函数返回0,如果循环了一遍beg发现找不到一棵生成树,那么mid就偏小了。
后来在poj上交这道题,稍微改那“一丝差别”时,才发现,自己这不是多搞出来一个二分的复杂度么。188ms与94ms的区别。
*/
解题思路:只需要一遍循环1<=beg<=m-n+2,求出所有生成树,对它们最大边全与最小边权的差取min就是答案了。
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int n, m, f[101];
struct edge{
int a, b, v;
bool operator < (edge i) const{
return v < i.v;
}
}e[5001];
int find(int x){
return f[x] = f[x] == x ? x : find(f[x]);
}
int kruskal(int beg){
int ed = 0, res;
for(int i = beg; i <= m && ed < n-1; i++){
int fa = find(e[i].a), fb = find(e[i].b);
if(fa != fb) f[fa] = fb, ed++, res = e[i].v - e[beg].v;
}
return ed == n-1 ? res : (1<<30);
}
int main()
{
while(scanf("%d %d", &n, &m) && n){
for(int i = 1; i <= n; i++) f[i] = i;
int cot = 1;
for(int i = 1; i <= m; i++){
scanf("%d %d %d", &e[i].a, &e[i].b, &e[i].v);
int fa = find(e[i].a), fb = find(e[i].b);
if(fa != fb) f[fa] = fb, cot++;
}
if(cot < n){
printf("-1\n"); continue;
}
sort(e+1, e+m+1);
int ans = (1<<30);
for(int beg = 1; beg <= m-n+2; beg++){
for(int i = 1; i <= n; i++) f[i] = i;
ans = min(ans, kruskal(beg));
}
printf("%d\n", ans);
}
return 0;
}