1、题目链接
2、首先把权值排序。对于连续的边集区间[L,R],如果这些边使n个点全部连通(用并查集,逐步扩大连通集),则存在。
从小到大枚举L,从R=L开始,添加n个边,用并查集将这些边的端点合为一个并查集。
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
#define N 5000+10
#define INF 100000000
int u[N], v[N], w[N]; //也可以struct edge
int r[N], p[N];
int n, m;
int find(int x)
{
return p[x] == x ? x : p[x] = find(p[x]);
}
int cmp(const int i, const int j)
{
return w[i] < w[j];
}
int Kruskal(int L)
{
int ans = -1;
int R;
for (int i = 1; i <= n; i++)//每构建一次即初始化一次并查集
p[i] = i;
for (R = L; R < m; R++)
{
int e = r[R];
int x = find(u[e]);
int y = find(v[e]);
if (x != y) //不构成圈
{
ans = max(ans, w[e] - w[r[L]]);
p[x] = y; //合成树,即添加边
}
}
int fa = find(1);
for (int i = 1; i <= n; i++)//判断n个点是否都连通
if (fa != find(i))
return ans=INF;
return ans;//连通就返回
}
int main()
{
while (cin >> n >> m && (n || m))
{
int ans = INF;
for (int i = 0; i < m; i++)
cin>>u[i]>>v[i]>>w[i]; //第i条边的数据
for (int i = 0; i < m; i++)
r[i] = i;
sort(r, r + m, cmp); //注意此处排序i的意义
if (m < n - 1)cout<<"-1\n";
else
{
for (int i = 0; i < m - n + 2; i++)
ans = min(ans, Kruskal(i));
if (ans == INF)
cout<<"-1\n";
else cout<<ans;
}
}
return 0;
}