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;
}
posted @ 2020-05-26 19:15  shuitiangong  阅读(151)  评论(0编辑  收藏  举报