B - Super Mancunian 并查集+思维

题目:https://vjudge.z180.cn/contest/423156#problem/B
题意:给一个连通图,求当把一条边的花费归成0时的最小生成树,并且求最少花费的所有路径数量

解析: 最小花费 = 并查集的最优解 - 最大路径的花费;
当求数量的时候可以用最优解往下跑,当遇到小于最大边的时候,这条边就是最优解的一部分,把它并起来,反之,当大于最大边时,不减成零的时候他一定不是最优解,但是当减成零的时候,剩下的边一定是最优解,因为咱们用的是最优解往下跑的,不是最优解的都没有并起来,所以他是一种解,当等于最大边的时候,他也是一种解;(另外,当判断是否是解的时候一定要判断是否成环,如果有环,那么它一定不是最优解,去掉任意一条边,也不是最优解。)

#include <bits/stdc++.h>
#define lowbit(x) x&(-x)
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const ll llINF = 0x3f3f3f3f3f3f3f3f;
const int INF = 0x3f3f3f3f;
const double DINF = 1e20;
const double eps = 1e-7;
const double PI = acos(-1.0);
const int mod = 1e9 + 7;
const int N = 2e5 + 50;

int n, m;
struct node
{
    
    
    int u, v, w;
    bool operator < (const node &other) const {
    
    
        return w < other.w;
    }
}e[N];

int f[N];
inline int Getf(int u)
{
    
    
    if (u != f[u]) f[u] = Getf(f[u]);
    return f[u];
}

int main()
{
    
    
    //ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);

    scanf("%d%d", &n, &m);

    for (int i = 0; i < m; i++) {
    
    
        scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w);
    }

    sort(e, e + m);

    int maxn = 0; ll res = 0;

    for (int i = 1; i <= n; i++) f[i] = i;

    for (int i = 0; i < m; i++) {
    
    
        int fx = Getf(e[i].u), fy = Getf(e[i].v);
        if (fx != fy) {
    
    
            f[fy] = fx;
            res += e[i].w;
            maxn = max(maxn, e[i].w);
        }
    }

    for (int i = 1; i <= n; i++) f[i] = i;

    int sum = 0;

    for (int i = 0; i < m; i++) {
    
    
        int fx = Getf(e[i].u), fy = Getf(e[i].v);
        if (fx != fy) {
    
    
            if (e[i].w >= maxn) sum++;
            else {
    
    
                f[fy] = fx;
            }
        }
    }

    printf("%lld %d\n", res - maxn, sum);

    return 0;
}

Guess you like

Origin blog.csdn.net/YingShen_xyz/article/details/113831380