HDU 5723 Abandoned country

题目说每条边权值都不一样,说明最小生成树是唯一的,不存在最小期望这一说。

然后就是先求出最小生成树,随便确定一个根节点,计算出每个点的子树有多少节点,记为c[x]。

指向x的这条边被统计的次数为c[x]*(n-c[x])。然后基本就可以算出答案了。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<iostream>
using namespace std;
typedef long long LL;

const int maxn = 100000 + 10;
int T, n, m, f[maxn], c[maxn];
bool flag[maxn];
struct Edge { int u, v; LL cost; }e[10 * maxn], ee[maxn]; 
vector<int>g[maxn];
double fz, fm;

int Find(int x) { if (x != f[x]) f[x] = Find(f[x]); return f[x]; }
bool cmp(const Edge&a, const Edge&b) { return a.cost < b.cost; }

void dfs(int x,int f)
{
    flag[x] = 1; c[x] = 1;
    for (int i = 0; i < g[x].size(); i++)
    {
        int id = g[x][i]; if (flag[ee[id].v]) continue;
        dfs(ee[id].v,id); c[x] = c[x] + c[ee[id].v];
    }
    if (f != -1)
        fz = fz + 1.0*ee[f].cost*1.0*c[x] * 1.0* (n - c[x]);
}

int main()
{
    scanf("%d", &T);
    while (T--) 
    {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= m; i++)
            scanf("%d%d%lld", &e[i].u, &e[i].v, &e[i].cost);
        sort(e + 1, e + 1 + m, cmp);
        LL ans = 0;
        for (int i = 1; i <= n; i++) f[i] = i, g[i].clear();
        int sz = 0;
        for (int i = 1; i <= m; i++)
        {
            int fx = Find(e[i].u), fy = Find(e[i].v);
            if (fx != fy)
            {
                f[fx] = fy, ans = ans + e[i].cost;
                ee[sz].u = e[i].u, ee[sz].v = e[i].v, ee[sz].cost = e[i].cost;
                g[e[i].u].push_back(sz++);
                ee[sz].u = e[i].v, ee[sz].v = e[i].u, ee[sz].cost = e[i].cost;
                g[e[i].v].push_back(sz++);
            }
        }
        memset(c, fz=0, sizeof c);
        memset(flag, fm=0, sizeof flag);  
        dfs(1, -1); 
        fm = 1.0*n*1.0*(n - 1) / 2.0;
        printf("%lld %.2lf\n", ans, fz / fm);
    }
    return 0;
}

 

posted @ 2016-07-21 22:14  Fighting_Heart  阅读(205)  评论(0编辑  收藏  举报