zoukankan      html  css  js  c++  java
  • 最小生成树+树上任意两点的最小期望

    参考博客

    题意:有n个城市,m条需要被重建的路,每条路有权值且各不相同,让你使所有城市相通(直接或间接)的情况下,找出权值和最小的那种方案,然后问你从这种方案中任意选取两点,问这两点之间的距离的最小期望值是多少。
    解题思路:让你找出权值和最小,当然是最小生成树啊,但是后面那个最小期望有点麻烦,不过我们可以仔细分析得到,每条路的权值都不一样所得出的最小生成树是唯一的(具体证明自己百度),那么生成树唯一,怎样在这棵树上求最小期望,最小期望?这其实是出题人忽悠你的,一棵树上任意两点之间的距离唯一,所以不存在最小最大之说,只要找出任意两两点之间的距离就行,然后把所有的距离加起来除以n*(n - 1)/2就行,那么问题就转化为在一无根树上求任意两点之间的距离之和,我们分析可以得到,所有距离之和等于每一条边的权值乘以这条边出现的次数之和,每一条边的权值我们知道,我们现在要知道每一条边出现过多少次,而我们可以发现,每条边出现的次数等于这条边的两个端点两侧`顶点数目的乘积,知道了这一点,我们就可以直接dfs了,任意选取一个顶点为根(我这里选的是1),令dp[u]等于以u为根的子树的顶点数,然后枚举每一条边,假如一条边的两个顶点是x1,x2,那么x1,x2中要么x1是x2的父亲,要么x2是x1的父亲,那么到底谁是谁的父亲,很简单,比较dp[x1],dp[x2],小的那个一定是孩子,所有这条边的一侧的顶点数为v1 = min(dp[x1],dp[x2]),那么另一侧顶点数是多少呢?很简单,总数是n ,所有另一侧顶点数v2 = n - v1,所有这条边出现的次数为v1v2,注意最后求期望除以n*(n - 1)/2时一定要将n,n - 1变成long long 之后再求,我在这里wa了无数次。

    代码:

    #include<stdio.h>
    #include<iostream>
    #include<algorithm>
    #include<vector>
    #include<string.h>
    typedef long long ll;
    using namespace std;
    const int max_=1e6+5;
    const int max_n=1e5+5;
    struct edge{
         int form;
         int to;
         ll w;
    };
    struct edge tu[max_],tree[max_n];
    int dp[max_n];//记录包自身的子树节点
    int fa[max_n];//父节点
    bool vis[max_n];//标记数组
    vector<int>g[max_n];//记录子节点
    int tot1,tot2;
    void add_edge1(int x,int y,ll w)//建图
    {
        tu[tot1].form=x;
        tu[tot1].to=y;
        tu[tot1++].w=w;
    }
    void add_edge2(int x,int y,ll w)//建树
    {
        tree[tot2].form=x;
        tree[tot2].to=y;
        tree[tot2++].w=w;
    }
    bool cmp(edge a,edge b)//排序
    {
        return a.w<b.w;
    }
    int find_fa(int x)//并查集
    {
        if(x==fa[x])
            return x;
        else
            return fa[x]=find_fa(fa[x]);
    }
    ll Kruskal(int n)//最小生成树算法
    {
        sort(tu,tu+tot1,cmp);
        int ans=0;
        ll ant=0;
        for(int i=0;i<tot1;i++)
        {
            int v=tu[i].form;
            int u=tu[i].to;
            ll w=tu[i].w;
            int f1=find_fa(v);
            int f2=find_fa(u);
            if(f1!=f2)
            {
                fa[f1]=f2;
                ant+=w;
                add_edge2(u,v,w);
                ans++;
                g[u].push_back(v);
                g[v].push_back(u);
            }
            if(ans==n-1)
            {
            return ant;
            }
        }
    }
    void dfs(int x)//dfs寻找树的子节点
    {
        vis[x]=true;
        dp[x]=1;
        for(int i=0;i<g[x].size();i++)
        {
            int y=g[x][i];
            if(!vis[y])
            {
                dfs(y);
                dp[x]+=dp[y];
            }
        }
    }
    void init(int n)//初始化
    {
        memset(vis,0,sizeof(vis));
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++)
        {
              fa[i]=i;
              g[i].clear();
        }
        tot1=0;
        tot2=0;
    }
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--)
        {
            int n,m;
          scanf("%d %d",&n,&m);
            ll ans=0;
            init(n);
            if(m==0)
            {
                  printf("0 0.00
    ");
                  continue;
            }
            while(m--)
            {
                int x,y;
                ll w;
                scanf("%d %d %lld",&x,&y,&w);
                add_edge1(x,y,w);
            }
            ll sum=Kruskal(n);
            dfs(1);
            for(int i=0;i<tot2;i++)
            {
                int u=tree[i].form;
                int v=tree[i].to;
                ll w=tree[i].w;
                int k=min(dp[v],dp[u]);
                ans+=w*(n-k)*k;
                //cout<<ans<<endl;
            }
           // printf("%.2f
    ",1.0*(n-1)*n/2);
            double expe=ans*1.0/(1.0*n*(n-1)/2);
            printf("%lld %.2lf
    ",sum,expe);
        }
    }
  • 相关阅读:
    图标线性回归移动到指定的位置
    jquery实现图片裁剪
    使用php输出时间格式
    《这些年,我们读过的技术经典图书》主题有奖征文
    JSON数据格式
    设计模式-命令模式
    windows vc6 release 调试
    hdu4530小Q系列故事——大笨钟
    设计模式-建造者模式
    设计模式-外观模式
  • 原文地址:https://www.cnblogs.com/linhaitai/p/9745275.html
Copyright © 2011-2022 走看看