2016 Multi-University Training Contest 1Abandoned country

qaq,现在内心真是各种草泥马。怪自己见识短浅。。。哎。。。
题意:
给你一幅图,然后求一个最小花费使得所有的点都连通(这就是最小生成树啊),然后在这棵树上【如果我要从任意起点到任意终点,这两个点不同,且这两个点的被选取概率都是一样,求一个最小的期望长度,我的神队友的解释就是树上所有任意不同点之间的边值都加起来然后除以边的数量】

思路:
①:最小生成树;
②:求一个所有边之和/边的数量,一个边的贡献,对总和的贡献,就是任意两点之和,这个边被加了多少次,那就用这个边把树分成两部分,一部分有a个点,一部分有b个。那这个边就被加了a*b个点,那这个边就被加了a*b个次。
= =、以上纯属YY,路人勿喷。

利用树的构造,查找儿子节点个数。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const double eps=1e-6;
const double pi=acos(-1.0);
const int mod=998244353;
const LL INF=0x3f3f3f3f;
const int N=1e5+10;
struct asd{
    int to;
    int next;
};
asd q[N];
int head[N],tol;
int sz[N];

void add(int a,int b)
{
    q[tol].to=b;
    q[tol].next=head[a];
    head[a]=tol++;
}

void dfs(int root,int father)
{
    sz[root]=1;
    for(int i=head[root];i!=-1;i=q[i].next)
    {
        int son=q[i].to;
        if(son==father) continue;
        dfs(son,root);
        sz[root]+=sz[son];
    }   
}

int main()
{
    int n,m;
    while(1){
        cin>>n>>m;
        tol=0;
        memset(head,-1,sizeof(head));
        for(int i=0;i<m;i++){
            int a,b;
            cin>>a>>b;
            add(a,b);
            add(b,a);
        }
        dfs(1,-1);
        for(int i=2;i<=n;i++){
            printf("第%d个点:\n",i);
            printf("左:%d  右:%d\n",sz[i],n-sz[i]);
        }
    }
}

这里写图片描述
qaq , 实在看不懂就只能调试知道算法…然后就会知道这个算法就是找该节点的儿子数目(包括他本身)。
然后边的权值就是节点到前面那个父亲节点的距离。找儿子这波操作真是血亏。。。智障题。。
比赛的时候数组还开小了…T了N发还以为不行。。。虽然后来证明是不行。。。
瞎扔一份代码跑….

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const double eps=1e-6;
const double pi=acos(-1.0);
const int mod=998244353;
const LL INF=0x3f3f3f3f;
const int N=1e5+10;
struct asd{
    int x,y;
    LL num;
};
struct ad{
    LL w;
    int to;
    int next;
};
ad ma[N*20];
int tol,head[N*20];

asd qq[N*10];
asd q[N*10];
int pre[N];
int vis[N];
int n;
LL val[N];
int sb[N];

bool cmp(asd z,asd x)
{
    if(z.num<x.num)
        return 1;
    return 0;
}
void Init()
{
    for(int i=1;i<=n;i++)
        pre[i]=i;
}
int Find(int x)
{
    int r=x;
    while(r!=pre[r])
    {
        r=pre[r];
    }
    int i=x,j;
    while(pre[i]!=r)
    {
        j=pre[i];
        pre[i]=r;
        i=j;
    }
    return r;
}
void add(int a,int b,LL c)
{
    ma[tol].w=c;
    ma[tol].to=b;
    ma[tol].next=head[a];
    head[a]=tol++;
}
void dfs(int u,int v)
{
    sb[u]=1;
    for(int i=head[u];i!=-1;i=ma[i].next){
        int tt=ma[i].to;
        if(tt==v) continue;
        val[tt]=ma[i].w;
        dfs(tt,u);
        sb[u]+=sb[tt];
    }
}
int main()
{
    int t;
    cin>>t;
    while(t--){
        int m,a,b;
        LL c;
        scanf("%d%d",&n,&m);
        LL temp;
        temp=(LL)n*(n-1)*0.5;
        Init();
        for(int i=0;i<m;i++)
        {
            scanf("%d%d%lld",&a,&b,&c);
            q[i].x=a;
            q[i].y=b;
            q[i].num=c;
        }
        sort(q,q+m,cmp);
        LL ans=0;
        tol=0;
        memset(head,-1,sizeof(head));
        for(int i=0;i<m;i++)
        {
            int aa=Find(q[i].x);
            int bb=Find(q[i].y);
            if(aa!=bb)
            {
                add(q[i].x,q[i].y,q[i].num);
                add(q[i].y,q[i].x,q[i].num);
                pre[aa]=bb;
                ans+=q[i].num;
            }
        }
        dfs(1,0);
        LL sum=0;
        for(int i=2;i<=n;i++){
            sum+=val[i]*sb[i]*(n-sb[i]);
        }
        if(n==1)
            printf("%lld 0.00\n",ans);
        else
            printf("%lld %.2lf\n",ans,(double)sum/(double)temp);
    }
    return 0;
}
/*

100
4 6
1 2 1
2 3 2
3 4 3
4 1 4
1 3 5
2 4 6
5 4
1 2 1
3 4 2
2 3 3
2 5 4
6 5
1 6 4
1 2 3
2 5 2
2 3 1
3 4 2
*/

posted @ 2016-07-19 16:48  see_you_later  阅读(142)  评论(0编辑  收藏  举报