传送门:http://www.lydsy.com:808/JudgeOnline/problem.php?id=2878

这题调了一上午加一下午,简直蛋疼。。。

n^2暴力很好想,就枚举每个点作为起点,然后再dfs一遍即可。然后我们发现在一棵树中,一个点只能向上走或向下走,于是就可以dp了。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <list>
#include <queue>
using namespace std;
const int maxn = 100010;
struct node {
    int x, val;
    node() {}
    node(int a, int b) {
        x = a; val = b;
    }
};
list <node> edge[maxn];
queue <int> q;
double up[maxn], down[maxn];
int cnt[maxn], dig[maxn];
bool vis[maxn];
int n, m;
double ans;
void dpd(int x, int fa) {
    int son = 0;
    for(list <node> :: iterator p = edge[x].begin(); p != edge[x].end(); p ++) {
        if(p -> x == fa) continue;
        dpd(p -> x, x);
        son ++;
    }
    for(list <node> :: iterator p = edge[x].begin(); p != edge[x].end(); p ++) {
        if(p -> x == fa) continue;
        down[x] += (down[p -> x] + p -> val) / (double)son;
    }
    return;
}
void dpu(int x, int fa) {
    int son = 0;
    double sum = 0;
    for(list <node> :: iterator p = edge[x].begin(); p != edge[x].end(); p ++) {
        if(p -> x == fa) continue;
        sum += p -> val + down[p -> x];
        son ++;
    }
    if(fa) {
        son ++;
        sum += up[x];
    } else {
        if(son == 1) {
            son ++;
        }
    }
    for(list <node> :: iterator p = edge[x].begin(); p != edge[x].end(); p ++) {
        if(p -> x == fa) continue;
        up[p -> x] = (sum - down[p -> x] - p -> val) / (double)(son - 1) + p -> val;
    }
    for(list <node> :: iterator p = edge[x].begin(); p != edge[x].end(); p ++) {
        if(p -> x == fa) continue;
        dpu(p -> x, x);
    }
}
void dfd(int x, int fa) {
    int son = 0;
    for(list <node> :: iterator p = edge[x].begin(); p != edge[x].end(); p ++) {
        if(p -> x == fa || !vis[p -> x]) continue;
        dfd(p -> x, x);
        son ++;
    }
    for(list <node> :: iterator p = edge[x].begin(); p != edge[x].end(); p ++) {
        if(p -> x == fa || !vis[p -> x]) continue;
        down[x] += (down[p -> x] + p -> val) / (double)son;
    }
    return;
}
void dfu(int x, int fa) {
    int son = 0;
    double sum = 0;
    for(list <node> :: iterator p = edge[x].begin(); p != edge[x].end(); p ++) {
        if(p -> x == fa || !vis[p -> x]) continue;
        sum += p -> val + down[p -> x];
        son ++;
    }
    if(!fa) {
        son += 2;
        sum += up[x] * 2;
    } else {
        son ++;
        sum += up[x];
    }
    for(list <node> :: iterator p = edge[x].begin(); p != edge[x].end(); p ++) {
        if(p -> x == fa || !vis[p -> x]) continue;
        up[p -> x] = (sum - down[p -> x] - p -> val) / (double)(son - 1) + p -> val;
    }
    for(list <node> :: iterator p = edge[x].begin(); p != edge[x].end(); p ++) {
        if(p -> x == fa || !vis[p -> x]) continue;
        dfu(p -> x, x);
    }
    return;
}
void solve(int x) {
    int nxt;
    double sum = 0, res = 0, g;
    for(list <node> :: iterator p = edge[x].begin(); p != edge[x].end(); p ++) {
        if(!vis[p -> x]) {
            nxt = p -> x;
            res = p -> val;
            int x1 = x;
            g = 0.5;
            while(nxt) {
                if(cnt[nxt] > 2) {
                    sum += (res + down[nxt]) * g * (double)(cnt[nxt] - 2) / (double)(cnt[nxt] - 1);
                    g /= (double)(cnt[nxt] - 1);
                }
                int tmp = 0;
                for(list <node> :: iterator p1 = edge[nxt].begin(); p1 != edge[nxt].end(); p1 ++) {
                    if(!vis[p1 -> x] && p1 -> x != x1 && p1 -> x != x) {
                        tmp = p1 -> x;
                        res += p1 -> val;
                        break;
                    }
                }
                x1 = nxt; nxt = tmp;
            }
            if(cnt[x1] == 2) {
                sum += res * g;
            } else {
                sum += (res + down[x1]) * g;
            }
        }
    }
    up[x] = sum;
    return;
}
int main() {
    scanf("%d%d", &n, &m);
    int u, v, w;
    for(int i = 1; i <= m; i ++) {
        scanf("%d%d%d", &u, &v, &w);
        edge[u].push_back(node(v, w));
        edge[v].push_back(node(u, w));
        cnt[u] ++; cnt[v] ++;
        dig[u] ++; dig[v] ++;
    }
    if(m == n - 1) {
        dpd(1, 0);
        dpu(1, 0);
        ans += down[1] / n;
        for(int i = 2; i <= n; i ++) {
            ans += (up[i] + down[i] * (cnt[i] - 1)) / cnt[i] / n;
        }
        printf("%.5lf\n", ans);
        return 0;
    }
    for(int i = 1; i <= n; i ++) {
        if(dig[i] == 1) q.push(i);
    }
    while(!q.empty()) {
        int t = q.front();
        q.pop();
        vis[t] = true;
        for(list <node> :: iterator p = edge[t].begin(); p != edge[t].end(); p ++) {
            if(!vis[p -> x]) {
                dig[p -> x] --;
                if(dig[p -> x] == 1) q.push(p -> x);
            }
        }
    }
    for(int i = 1; i <= n; i ++) {
        if(!vis[i]) dfd(i, 0);
    }
    for(int i = 1; i <= n; i ++) {
        if(!vis[i]) solve(i);
    }
    for(int i = 1; i <= n; i ++) {
        if(!vis[i]) dfu(i, 0);
    }
    for(int i = 1; i <= n; i ++) {
        ans += (up[i] * dig[i] + down[i] * (cnt[i] - dig[i])) / cnt[i] / n;
    }
    printf("%.5lf\n", ans);
    return 0;
}