UVAlive6807 Túnel de Rata (最小生成树)

题意

题目链接

Sol

神仙题Orz

我们考虑选的边的补集,可以很惊奇的发现,这个补集中的边恰好是原图中的一颗生成树;

并且答案就是所有边权的和减去这个边集中的边的权值;

于是我们只需要求最大生成树就好了;

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e6 + 10, INF = 1e9 + 10;
inline int read() {
    char c = getchar(); int x = 0, f = 1;
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}
int N, M, T, val, ans, f[MAXN];
struct Edge {
    int u, v, w;
    bool operator < (const Edge &rhs) const {
        return w > rhs.w;
    }
}E[MAXN];
int fa[MAXN];
int find(int x) {
    return fa[x] == x ? fa[x] : fa[x] = find(fa[x]);
}
void Kruskal() {
    memset(f, 0, sizeof(f));
    val = -1; ans = 0;
    sort(E + 1, E + M + 1);
    for(int i = 1; i <= N; i++) fa[i] = i;
    for(int i = 1; i <= M; i++) {
        int x = E[i].u, y = E[i].v, w = E[i].w, fx = find(x), fy = find(y);
        if(fx == fy) continue;
        fa[fx] = fy; f[i] = 1;
        ans += w;
    }
    for(int i = 1; i <= M; i++) if(!f[i]) {val = E[i].w; break;}
}
int main() {
//  freopen("a.in", "r", stdin);
    T = read();
    for(int i = 1; i <= T; i++) {
        N = read(); M = read(); int sum = 0;
        for(int j = 1; j <= M; j++) E[j].u = read(), E[j].v = read(), E[j].w = read(), sum += E[j].w;
        Kruskal();
        printf("Case #%d: %d %d\n", i, sum - ans, val);
    }
    return 0;
}
posted @ 2018-12-29 17:39  自为风月马前卒  阅读(204)  评论(0编辑  收藏  举报

Contact with me