• 清北学堂模拟赛d6t5 侦探游戏


    分析:简化一下题意就是给任意两对点连一条权值为0的边,求出每次连边后最小生成树的权值和*2/(n - 1) * n.

          每次求最小生成树肯定会爆炸,其实每次加边只是会对最小生成树上的一条边有影响,也就是加入这条边权为0的边后形成的环上权值最大的边,我们可以每次在树上倍增找到这条边,可以通过60%的点.

          最小生成树的变形题都有一个思路,就是当我们无法继续优化的时候我们就思考一下克鲁斯卡尔算法的原理,因为每条边是按照边权从小到大加入的,所以在加入这条边的时候,这条边两端连的点对之间连一条权值为0的边,所形成的环上的最大权值的边一定是新加入的这条边,利用乘法原理统计一下点对数就可以了.

    #include <bits/stdc++.h>
    
    using namespace std;
    int n,m,fa[20010],num[20010];
    long long cnt,ans;
    
    struct node
    {
        int u,v,w;
    }e[100010];
    
    bool cmp(node a,node b)
    {
        return a.w < b.w;
    }
    
    int find(int x)
    {
        if (x == fa[x])
            return x;
        return fa[x] = find(fa[x]);
    }
    
    void hebing(int x,int y)
    {
         num[x] += num[y];
         num[y] = 0;
         fa[y] = x;
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for (int i = 1; i <= n; i++)
        {
            fa[i] = i;
            num[i] = 1;
        }
        for (int i = 1; i <= m; i++)
            scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
        sort(e + 1,e + 1 + m,cmp);
        for (int i = 1; i <= m; i++)
        {
            int fu = find(e[i].u),fv = find(e[i].v);
            if (fu != fv)
            {
                ans += e[i].w;
                cnt += 1LL * num[fu] * num[fv] * e[i].w;
                hebing(fu,fv);
            }
        }
        double temp = ans - 2.0 * cnt / n / (n - 1);
        printf("%.2lf",temp);
    
        return 0;
    }
  • 相关阅读:
    react常用的方法
    react手动搭建
    js基础
    原生JavaScript实例之简单放大镜
    ||与&&的返回值
    promise简单小结
    连接服务器一般步骤
    github小总结
    __proto__指向问题
    一些函数返回值
  • 原文地址:https://www.cnblogs.com/zbtrs/p/7635682.html
Copyright © 2020-2023  润新知