Codeforces 101 D. Castle
問題
重み付き無向木が与えられる。
木のそれぞれのノードには宝が埋まっている。
ノード1から出発して、グラフの全部のノードを辿るように探索し、宝の埋まっているノードにたどり着いた瞬間に宝をする。
ただし、同じ辺は2度までしか通ることができない。
最適な順序でノードを辿ったときの宝の発見までの時間の期待値を求めよ。
制約条件
n≦10^5
方針
ノードv以下の全てのノードを辿って戻ってくるのにかかる時間をsum[v]
ノードvを出発して、vの子ノードを全て辿ったときに宝の発見時間に合計される値をdp[v]とする。
vの子ノードについて全てsumとdpが求まっているとき、
子ノードをどう辿るのが最善であるか。
例えばvには3つの子c1,c2,c3があって、c1→c2→c3の順に訪問するとする。
すると、宝の発見時間に合計される値は、
d[v][c1]*cld[c1] + dp[c1] + (2*d[v][c1]+sum[c1])*(cld[c2]+cld[c3]) + d[v][c2]*cld[c2] + dp[c2] + (2*d[v][c2]+sum[c2])*cld[c3] + d[v][c3]*cld[c3] + dp[c3]
のような形になることがわかる。
ここで、c2とc3の訪問順序を入れ替えると、
差分は(2*d[v][c2]+sum[c2])*cld[c3]-(2*d[v][c3]+sum[c3])*cld[c3]になる。
すなわち、辺を(2*d[v][c]+sum[c])/cld[c]の順にソートしてやれば、最適になることがわかる。
ソースコード
int n; vector<vector<pi> > g; double dp[100000],sum[100000]; int cld[100000]; bool cmp(pair<pair<double,double>,pi> a,pair<pair<double,double>,pi> b){ return a.first.first*b.first.second<b.first.first*a.first.second; } void rec(int c,int p){ double res=0; vector<pair<pair<double,double>,pi> > v; cld[c]=1; rep(i,g[c].size()){ int to=g[c][i].first, cost=g[c][i].second; if(to==p)continue; rec(to,c); sum[c]+=cost*2+sum[to]; cld[c]+=cld[to]; v.pb(mp(mp(sum[to]+cost*2,cld[to]),mp(to,i))); } sort(all(v),cmp); int num=cld[c]-1; rep(i,v.size()){ int to=v[i].second.first, cost=g[c][v[i].second.second].second; if(to==p)continue; num-=cld[to]; res+=dp[to]+cld[to]*cost+(cost*2+sum[to])*num; } dp[c]=res; } void run(){ cin>>n; g.resize(n); rep(i,n-1){ int a,b,c; cin>>a>>b>>c; g[--a].pb(mp(--b,c)); g[b].pb(mp(a,c)); } rec(0,-1); printf("%.9f\n",dp[0]/(n-1)); }