hdu 5723 Abandoned country 最小生成树+DFS

hdu 5723 Abandoned country 最小生成树+DFS

题目链接hdu 5723 Abandoned country
题意:给定N个顶点M条边的无向图,每条边包含一个权值,权值都 各不相同,求最小生成树并求最小生成树上的任意两点之间距离的最小期望。
分析:因为边权值各不相同,那么最小生成树是唯一的。那么只需要求最小生成树上的任意两点之间的距离之和除以N*(N-1)/2即可。对于求树上的任意两点之间的距离之和,我们可以从根节点DFS出发遍历求出每个结点的子树下的节点数之和+该节点本身的数目,记为sum[root]。然后考虑每个结点和它父亲节点的边,因为这条边的一端有sum[root]个节点,另外一端有N-sum[root]的节点,该边对于整个距离和的贡献就是(N-sum[root]) * 这条边的权值。那么时间复杂度就是O(Elog(E)+N)。思路同:  hdu 2376 Average distance
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;

//#pragma comment(linker, "/STACK:1024000000,1024000000")

#define FIN             freopen("input.txt","r",stdin)
#define FOUT            freopen("output.txt","w",stdout)
#define fst             first
#define snd             second

typedef __int64  LL;
//typedef long long LL;
typedef unsigned int uint;
typedef pair<int, int> PII;

const int INF = 0x3f3f3f3f;
const double eps = 1e-6;
const int MAXN = 100000 + 5;
const int MAXM = 1000000 + 5;
struct Edge {
    int u, v, w;
    bool operator < (const Edge& e) const {
        return w < e.w;
    }
} edges[MAXM];
int T, N, M;
int par[MAXN], _rank[MAXN];
struct TNode {
    int v, w;
    TNode() {}
    TNode(int v, int w) : v(v), w(w) {}
};
vector<TNode> G[MAXN];
LL sum[MAXN];
LL ans;
void init() {
    memset(par, -1, sizeof(par));
    memset(_rank, 0, sizeof(_rank));
    // memset(vis, false, sizeof(vis));
    memset(sum, 0, sizeof(sum));
    for (int i = 1; i <= N; i++) G[i].clear();
}

int Find(int x) {
    return -1 == par[x] ? x : (par[x] = Find(par[x]));
}

LL Kruskal() {
    LL cost = 0;
    int ecnt = 0;
    init();
    sort(edges, edges + M);
    for (int i = 0; i < M && ecnt < N - 1; i++) {
        Edge& e = edges[i];
        int pu = Find(e.u);
        int pv = Find(e.v);
        if (pu == pv) continue;
        if (_rank[pu] == _rank[pv]) {
            par[pv] = pu;
            _rank[pu] ++;
        } else if (_rank[pu] > _rank[pv]) {
            par[pv] = pu;
        } else {
            par[pu] = pv;
        }
        cost += e.w;
        Find(e.u);
        Find(e.v);
        ecnt ++;
        G[e.u].push_back(TNode(e.v, e.w));
        G[e.v].push_back(TNode(e.u, e.w));
    }
    return cost;
}

void dfs(int root, int father) {
    sum[root] = 1;
    for (int i = 0; i < G[root].size(); i++) {
        TNode& e = G[root][i];
        int son = e.v;
        if (son == father) continue;
        dfs(son, root);
        sum[root] += sum[son];
        ans += (sum[son] * (N - sum[son])) * e.w;
    }
}

int main() {
#ifndef ONLINE_JUDGE
    FIN;
#endif // ONLINE_JUDGE
    scanf("%d", &T);
    while (T --) {
        scanf("%d %d", &N, &M);
        int u, v, w;
        for (int i = 0; i < M; i++) {
            scanf("%d %d %d", &u, &v, &w);
            edges[i].u = u;
            edges[i].v = v;
            edges[i].w = w;
        }
        LL mincost = Kruskal();
        ans = 0;
        dfs(1, -1);
        LL s = (LL)N * (N - 1) / 2;
        printf("%lld %.2lf\n", mincost, (double) ans / s);
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值