2016 Multi-University Training Contest 1 Abandoned country

这题先求出最小生成树,然后在最小生成树中求任意两个点之和的平均数。。因为最小生成树是唯一的,所以期望也就只有一个。求最小生成树的时候把树存起来。求任意两点之和的时候我们求出一条边在求和的时候用了多少次,也就是求该边的左右端点有多少个比如一条边左右两边有A,B个端点,那么利用的次数也就是A*B。
我们可以用dfs来实现,用sum数组表示k点子树上的点(包括他自己),那么kf父亲那边的点就是n-sum[k]。最后载除一个n*(n-1)/2就可得到答案。

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<map>
#include<set>
#include<vector>
using namespace std;
const int N=100005;
const int maxn=1001000;
struct node
{
    int v;
    __int64 len; 
};
vector<node>G[2*N];
struct Node
{
    int u,v;
    __int64 w;  
};
int tol;
Node edge[2*maxn];
void addedge(int u,int v,__int64 w)
{
    edge[tol].u=u;
    edge[tol].v=v;
    edge[tol++].w=w;
}
double dp;
__int64 sum[N];
int f[N];
__int64 n;
int m;
bool cmp(Node a,Node b)
{
    return a.w<b.w;
} 
int find(int x)
{
    return f[x]==x?x:f[x]=find(f[x]);
}
__int64 kulasal()
{
    __int64 ans=0;
    for(int i=1;i<=n;i++)
    f[i]=i;
    int cnt=0;
    sort(edge,edge+tol,cmp);
    for(int i=0;i<tol;i++)
    {
        int u=edge[i].u;
        int v=edge[i].v;
        int w=edge[i].w;
        int fx=find(u);
        int fy=find(v); 
        if(fx!=fy)
        {
            f[fx]=fy;
            ans+=w;
            node p1,p2;
            p1.v=u;
            p1.len=w;
            p2.v=v;
            p2.len=w;
            G[u].push_back(p2);
            G[v].push_back(p1); 
            cnt++;
        }
        if(cnt==n-1)
        break;
    }
    return ans;
}
void dfs(int root,int father)
{
    sum[root]=1;
    for(int i=0;i<G[root].size();i++)
    {
        int son=G[root][i].v;
        int len=G[root][i].len;
        if(son==father)
        continue;
        dfs(son,root);
        sum[root]+=sum[son];
        dp+=(sum[son]*(n-sum[son]))*(double)len;
    }
}
int main()
{
         int T;
         scanf("%d",&T);
         while(T--)
         {
         tol=0;
         for(int i=1;i<=n;i++)
         G[i].clear();
        scanf("%I64d %d",&n,&m);
        for(int i=0;i<m;i++)
        {
            int u,v,w;
            scanf("%d %d %64d",&u,&v,&w);
            addedge(u,v,w);
            addedge(v,u,w);
        } 
         __int64 S=kulasal();
         memset(sum,0,sizeof(sum));
         dp=0;
         dfs(1,-1);
         __int64 s=n*(n-1)/2;
         double ans=dp/(double)s;
         printf("%I64d %0.2f
",S,ans); 
    }
    return 0;
} 

原文地址:https://www.cnblogs.com/NaCl/p/9580113.html