题目链接:http://poj.org/problem?id=2395
题意:求一棵生成树使最大的边和最小的边差值最小。
思路:n很小,所以用kruskal直接从最小边开始枚举,一直往大的判断边,组成一棵生成树就停止,判断此时的差值,然后又从第二小的边开始往上遍历,重复操作。
这么做对的理由是因为排好了序,从小往大遍历使得枚举一次的结果一定是暂时最小的,那么从小到大依次枚举使得全部边都参与进来,所以所有暂时解的最小就是答案
代码:
#include <cstdio>
#include <cmath>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <numeric>
#include <set>
#include <string>
#include <cctype>
#include <sstream>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
typedef pair<int, int> P;
const int maxn = 1e2 + 5;
int n, m, p[maxn], q, cnt;
void init (int n) {
for (int i = 0; i <= n; i++) p[i] = i;
}
int Find(int x) {
return p[x] == x ? x : ( p[x] = Find ( p[x] ) );
}
bool same(int a, int b) {
return Find(a) == Find(b);
}
void unite (int x, int y) {
x = Find(x);
y = Find(y);
if (x != y) p[x] = y;
}
struct edge {
int u, v, cost;
} e[10005];
bool cmp(edge x, edge y) {
return x.cost < y.cost;
}
int kruscal() {
sort(e, e + cnt, cmp);
int ans=INF;
for (int j = 0; j <= cnt - n + 1; j++) {
init(n);
int num=0;
for (int i = j; i < cnt; i++) {
int x = Find(e[i].u), y = Find(e[i].v);
if (x != y) {
num++;
unite(e[i].u, e[i].v);
if (num==n-1){
ans=min(ans,e[i].cost-e[j].cost);
break;
}
}
}
}
return ans;
}
int main() {
while (~scanf ("%d%d", &n, &m)&&n) {
cnt = 0;
while (m--) {
int u, v, cost;
scanf ("%d%d%d", &u, &v, &cost);
e[cnt].u = u;
e[cnt].v = v;
e[cnt++].cost = cost;
}
int ans = kruscal();
if (ans==INF) printf ("-1\n");
else printf ("%d\n", ans);
}
return 0;
}