51Nod 1640 天气晴朗的魔法(最小生成树)
解题思路
看这题第一眼就想到了二分,虽然也过了不过还有一个更好的解法。本题的核心就是如何找到那条可以最小的最大的边\(S\),二分确实是一个办法,但是还有一种办法是求最小生成树,其最大边就是\(S\)。
因为最小生成树是将几条不重复的最小的边加入集合形成的树,那么如果要构造一棵树都所有边比最小生成树的最大边还小的话,是不可能的,不然,那棵最小生成树就不是最小生成树了,也可以说,根本构造不出来一棵这样的树。
求出\(S\)之后就好办了,只需要构造一棵最大的生成树,其最大的边不超过\(S\)即可。
代码
const int maxn = 2e5+10;
int n, m, p[maxn]; ll ans, maxx=-1;
struct E {
int u, v; ll w;
} e[maxn];
int find(int x) {
return p[x]==x ? p[x] : p[x] = find(p[x]);
}
void merge(int a, int b) {
p[find(a)] = find(b);
}
void kruskal(ll x) {
ll sum = 0;
for (int i = 1; i<=n; ++i) p[i] = i;
for (int i = 0; i<m; ++i)
if (e[i].w<=x && find(e[i].u)!=find(e[i].v)) {
merge(e[i].u, e[i].v);
sum += e[i].w;
maxx = max(maxx, e[i].w);
}
ans = sum;
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 0; i<m; ++i) scanf("%d%d%lld", &e[i].u, &e[i].v, &e[i].w);
sort(e, e+m, [](E a, E b){return a.w<b.w;});kruskal(LLONG_MAX);
sort(e, e+m, [](E a, E b){return a.w>b.w;});kruskal(maxx);
printf("%lld\n", ans);
return 0;
}