hdu5723(树形dp+最小生成树)

链接:点击打开链接

题意:在最小生成树的基础上求出任意两点间距离的期望

代码:

#include <vector>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;
const long long SIZE=100005;
long long n,dp[SIZE],num[SIZE],used[SIZE];
struct node{
    long long to,cost;
};
vector<node> G[SIZE];
void dfs1(long long s,long long sum){
    long long i,tmp;
    dp[1]+=sum;                                 //求出根节点的到其他节点的和
    used[s]=1;                                  //和每个节点的子节点数
    for(i=0;i<G[s].size();i++){
        tmp=G[s][i].to;
        if(!used[tmp]){
        dfs1(tmp,sum+G[s][i].cost);
        num[s]+=num[tmp];
        }
    }
}
void dfs2(long long s){
    long long i,tmp;
    used[s]=1;
    for(i=0;i<G[s].size();i++){
        tmp=G[s][i].to;
        if(!used[tmp]){
        dp[tmp]+=(dp[s]+(n-num[tmp])*G[s][i].cost-num[tmp]*G[s][i].cost);
        dfs2(tmp);
        }                                       //根据每个节点儿子节点的个数求出每个节点
    }                                           //到其他所有节点的和
}
long long V,E;
long long par[100005],ran[100005],vis[100005];
void init(long long n){
    long long i;
    for(i=0;i<=n;i++){
        ran[i]=0;
        par[i]=i;
    }
}
long long find(long long x){
    if(par[x]==x)
    return x;
    return par[x]=find(par[x]);
}
void unite(long long x,long long y){
    x=find(x);
    y=find(y);
    if(x==y)
    return;
    if(ran[x]<ran[y])
    par[x]=y;
    else{
        par[y]=x;
        if(ran[x]==ran[y])
        ran[x]++;
    }
}
bool same(long long x,long long y){
    return find(x)==find(y);
}
struct node1{
    long long u,v,cost;
};
bool cmp(node1 a,node1 b){
    return a.cost<b.cost;
}
node1 es[1000005];
long long kruskal(){
    long long i;
    long long res=0;
    init(V);
    sort(es,es+E,cmp);
    for(i=0;i<E;i++){
        node1 e=es[i];
        if(!same(e.u,e.v)){
            unite(e.u,e.v);
            G[e.u].push_back((node){e.v,e.cost});
            G[e.v].push_back((node){e.u,e.cost});
            res+=e.cost;
        }
    }
    return res;
}                                               //最小生成树
int main(){                                     //跟51nod1405几乎一样
    long long a,b,w,m,i,t,ans,sum;              //http://blog.csdn.net/stay_accept/article/details/50835286
    scanf("%I64d",&t);
    while(t--){
        scanf("%I64d%I64d",&n,&m);
        V=n,E=m;
        for(i=1;i<=n;i++)
        G[i].clear();
        memset(vis,0,sizeof(vis));
        for(i=0;i<E;i++)
        scanf("%I64d%I64d%I64d",&es[i].u,&es[i].v,&es[i].cost);
        ans=kruskal();
        fill(num,num+n+1,1);
        memset(dp,0,sizeof(dp));
        memset(used,0,sizeof(used));
        dfs1(1,0);
        memset(used,0,sizeof(used));
        dfs2(1);
        sum=0;
        for(i=1;i<=n;i++)
        sum+=dp[i];
        printf("%I64d %.2lf\n",ans,sum*1.0/(n*(n-1)));
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值