HDU

来源:互联网 发布:最好的网络电话软件 编辑:程序博客网 时间:2024/06/05 08:51

题意:有n个村庄,m条道路,要求寻找n个村庄的最小生成树,并且求出最小生成树中任意两点距离的期望

思路:最小生成树用模板生成,因为选中任意一对点的概率都是相同的,所以期望就是任意两点距离的和除以总情况数n*(n-1)/2

求任意两点间距离的和暴力循环O(n^2)的话会超时,可以用dfs,任意两点间距离的和其实是【最小生成树中所有边被访问次数*该边的权】的和。

要求被访问次数,可以先求以该边一节点为根节点的子树的节点总数num(包括这一节点,不包括该边的另一节点, 这里有点绕,参考下面例子),想要到达num个子节点就必须通过该边num次,同理该边的另一节点的子节点数一定是n-num,要通过改变n-num次,所以改变被通过次数时num*(n-num)次,推广到所有边,求和即可。

关于比较绕口的那句话举例:

在纸上画一棵树:

1 2

2 3

2 4

边1——2中:

以2为根节点的子树:

2 3

2 4

共有3个节点,要想达到这三个节点需要通过边1——2三次(对应点12、 13 、 14之间的距离)

以1位为根节点的子树只有1(这里一定是n-num次,仔细想一想),,所以只有一个节点,想要由其子节点到达边1——2只需要通过边1——2一次

所以边1——2一共被访问了1*3 = 3次

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#include <vector>using namespace std;typedef long long ll;typedef pair<int, int> P;const int maxn = 100000 + 10;const int maxm = 1000000 + 10;int n, m, par[maxn], num[maxn], vis[maxn];double ans;struct Edge {    int from, to, cost;    bool operator < (const Edge &e) {        return cost < e.cost;    }}edge[maxm];vector<P> g[maxn];void init() {    for (int i = 0; i <= n; i++) {            par[i] = i;            g[i].clear();        }        memset(num, 0, sizeof(num));        memset(vis, 0, sizeof(vis));        ans = 0.0;}int seek(int x) { return par[x] == x ? x : par[x] = seek(par[x]); }void dfs(int cur) {    num[cur] = 1;    vis[cur] = 1;    for (int i = 0; i < g[cur].size(); i++) {        int son = g[cur][i].first;        if (vis[son]) continue;        dfs(son);        num[cur] += num[son];        ans += 1.0 * num[son] * (n - num[son]) * g[cur][i].second;    }}int main() {    int T; scanf("%d", &T);    while (T--) {        scanf("%d %d", &n, &m);        init();        for (int i = 0; i < m; i++) {            scanf("%d %d %d", &edge[i].from, &edge[i].to, &edge[i].cost);        }        sort(edge, edge + m);        ll sum = 0, cnt = 0;        for (int i = 0; i < m && cnt < n - 1; i++) {            int f = edge[i].from, t = edge[i].to, c = edge[i].cost;            int x = seek(f), y = seek(t);            if (x != y) {                par[x] = y;                sum += c;                cnt++;                g[f].push_back(make_pair(t, c));                g[t].push_back(make_pair(f, c));            }        }        dfs(1);        printf("%lld %.2lf\n", sum, ans/(1.0 * n * (n - 1) / 2));    }    return 0;}