zoukankan      html  css  js  c++  java
  • 清北学堂模拟赛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;
    }
  • 相关阅读:
    树莓派安装parrot linux记录
    Arch linux(UEFI+GPT)安装及后续优化教程
    VS部分安全函数用法
    C语言博客作业06--结构体&文件
    C语言博客作业05--指针
    C语言博客作业04--数组
    C语言博客作业03--函数
    C语言博客作业02--循环结构
    DS博客作业08--课程总结
    DS博客作业07--查找
  • 原文地址:https://www.cnblogs.com/zbtrs/p/7635682.html
Copyright © 2011-2022 走看看