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
*/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值