传送门: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; }