2016 多校第一场 hdu 5723(最小生成树+dfs)

题解:跑一遍最小生成树,因为每条边长度不同所以跑不出来的答案就只有一种,对于求解任意两点的期望,只要把任意两点的距离累加和再除以总数即可,对于计算累加和,我借鉴了别人的方法,对于每条边,算出它左边有n个点,右边有m个点,那么这条边就会被用到n*m次 ,对所有的边都这么算一遍,答案累加就可以了


#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <string>
#include <map>
#include <math.h>
#include <queue>
#include <climits>
#include <stack>
using namespace std;

struct node {
    int op, ed;
    int len;
    bool operator<(const node &x)const{
        return len < x.len;
    }
}edge[1000005];
int father[100005], ret[1000005], dep[100005];
int cnt;
int n, m;
vector<int> graph[100005];


int find_(int x)
{
    if(father[x] == x)
        return x;
    else
        return father[x] = find_(father[x]);
}

int dfs(int now, int pre)
{
    int ans = 1;
    for(int i = 0; i < graph[now].size(); i++){
        if(graph[now][i] != pre)
            ans += dfs(graph[now][i], now);
    }
    dep[now] = ans;
    return ans;
    
}
void init()
{
    for(int i = 1; i <= n; i++)
        father[i] = i;
    memset(dep, 0, sizeof(dep));
}
long long kruskal()
{
    long long answer = 0;
    sort(edge, edge + m);
    for(int i = 0; i < m; i++){
        int a = edge[i].op, b = edge[i].ed;
        int x = find_(a), y = find_(b);
        if(x == y) continue;
        father[x] = y;
        ret[cnt++] = i;
        answer += edge[i].len;
        graph[a].push_back(b);
        graph[b].push_back(a);
        if(cnt == n - 1) break;
    }
    return answer;
}
int main()
{
    int t;
    scanf("%d", &t);
    while(t--){
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; i++)
            graph[i].clear();
        cnt = 0;
        for(int i = 0; i < m; i++)
            scanf("%d %d %d", &edge[i].op, &edge[i].ed, &edge[i].len);
        init();
        long long ans1 = kruskal();
        double sum1 = 0;
        dfs(1, -1);
        for(int i = 0; i < cnt; i++){
            int x = edge[ret[i]].op, y = edge[ret[i]].ed;
            int tmp = min(dep[x], dep[y]);
            int maxn = n - tmp;
            sum1 += 1ll * tmp * maxn * edge[ret[i]].len;
        }
        printf("%lld %.2lf\n", ans1, sum1 / (1ll * n * (n - 1) / 2));
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值