题意
给出n个点m条边,求生成树最大边与最小边的最小差值。
思路
把边排序一遍,按最小生成树模板进行加边,若碰到环则搜索环中最小的边,并将其删去。当边数等于n-1时即可获得答案,取最小值输出即可。
代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <set>
using namespace std;
const int N = 3e5;
const int M = 400;
int e[N], ne[N], h[M], w[N], f[M], idx = 0;
void add(int u, int v, int val) { e[++idx] = v, ne[idx] = h[u], h[u] = idx, w[idx] = val; }
int find(int x) { return f[x] == x ? x : f[x] = find(f[x]); }
struct edge
{
int u, v, w;
bool operator<(const edge& rhs)const { return w < rhs.w; }
}es[N], res;
int target;
bool dfs(int u, int fa)
{
if (u == target)return true;
for (int i = h[u]; i; i = ne[i])
{
int v = e[i];
if (v == fa)continue;
if (dfs(v, u))
{
if (res.w > w[i])
res.u = u, res.v = v, res.w = w[i];
return true;
}
}
return false;
}
void del(int u, int v)
{
for (int i = h[u], pre = 0; i; pre = i, i = ne[i])
if (e[i] == v)
{
if (!pre)h[u] = ne[i];
else ne[pre] = ne[i];
return;
}
}
int n, m;
multiset<int> se;
void solve()
{
idx = 0;
se.clear();
memset(h, 0, sizeof h);
for (int i = 1; i <= n; i++)f[i] = i;
sort(es + 1, es + 1 + m);
int cnt = 0, ans = 1e9;
for (int i = 1; i <= m; i++)
{
int u = find(es[i].u), v = find(es[i].v);
if (u != v) f[v] = u, cnt++;
else
{
res.w = 1e9, target = es[i].v;
dfs(es[i].u, 0);
del(res.u, res.v);
del(res.v, res.u);
se.erase(se.find(res.w));
//printf("%d<=/=>%d\n", res.u, res.v);
}
add(es[i].u, es[i].v, es[i].w);
add(es[i].v, es[i].u, es[i].w);
se.insert(es[i].w);
//printf("%d<===>%d\n", es[i].u, es[i].v);
if (cnt == n - 1)
{
int maxx = *se.rbegin(), minx = *se.begin();
ans = min(ans, maxx - minx);
}
}
if (cnt != n - 1)puts("-1");
else printf("%d\n", ans);
}
int main()
{
while (~scanf("%d", &n) && n && ~scanf("%d", &m))
{
for (int i = 1; i <= m; i++)
scanf("%d%d%d", &es[i].u, &es[i].v, &es[i].w), es[i].u++, es[i].v++;
solve();
}
return 0;
}