Description
Located at the easternmost tip of Shandon Peninsula, Weihai is one of the most famous tourist destinations all over China. There are beautiful hills, seas, bays, springs, islands, and beautiful beaches in Weihai. It is also a coastal city abundant in seafood, including prawn, sea cucumber, abalone, shellfish, and algae.
Attracted by the distinctive scenery and pleasant environment, three theoretical computer scientists plan to have a trip to Weihai. However, they cannot reach a consensus on accommodation, since some people prefer some hotels while other people like others. They decide to stay in separate hotels at night and meet in one hotel the next day. The hotel they meet may not necessarily be one of the hotels they stay in.
There are some roads connecting the hotels in Weihai. The roads are specially designed such that there is a unique path between every pair of hotels. Every theoretical computer scientist has prepared a list of candidate hotels before their trip starts. When they arrive in Weihai, each of them will uniformly and independently choose one hotel from the candidate hotel list. Also, they will meet in a hotel such that the total length of their routes is minimized. As a member of the theoretical computer science group, can you tell the expected total length of their routes?
Input Specification:
The first line of the input contains a single integer n ( 1 ≤ n ≤ 200000 ) n (1≤n≤200000) n(1≤n≤200000), denoting the number of hotels in Weihai. Then follow n − 1 n−1 n−1 lines, describing the roads connecting the hotels. Each of the n − 1 n−1 n−1 lines contains three integers u , v , w ( 1 ≤ u , v ≤ n , u ≠ v , 1 ≤ w ≤ 1000 ) u,v,w (1≤u,v≤n,u≠v,1≤w≤1000) u,v,w(1≤u,v≤n,u=v,1≤w≤1000), denoting a road of length w w w connecting the hotels numbered u u u and v v v. It is guaranteed that there is a unique path between every pair of hotels.
The last three lines of the input specify the candidate hotel lists, one for each theoretical computer scientist. Each line begins with a single integer m ( 1 ≤ m ≤ n ) m (1≤m≤n) m(1≤m≤n) and m m m distinct integers a 1 , a 2 , ⋯ , a m ( 1 ≤ a i ≤ n ) a1,a2,⋯,am (1≤ai≤n) a1,a2,⋯,am(1≤ai≤n), meaning that the candidate hotel list contains the hotels numbered a 1 , a 2 , ⋯ , a m a1,a2,⋯,am a1,a2,⋯,am.
Output Specification:
Print the expected total length of their routes within an absolute or relative error of no more than 1 0 − 6 10^{-6} 10−6.
Sample Input 1:
3
1 2 1
2 3 2
1 1
1 2
1 3
Sample Output 1:
3
Sample Input 2:
5
1 2 3
1 3 5
2 4 7
2 5 11
3 2 4 5
4 1 2 3 5
2 1 3
Sample Output 2:
13.958333333333
分析
这题比赛的时候只在最后十几分钟时瞟了一眼,赛后再看还是不会做。看别人题解把这题转化成换根DP问题的那一刻才感觉感觉茅塞顿开。
给定一棵带权树,以及三个标记点列表 L 1 , L 2 , L 3 L1,L2,L3 L1,L2,L3,求 m i n ∑ { d i s ( u 1 i , v ) + d i s ( u 2 i , v ) + d i s ( u 3 i , v ) } , min\sum{\{dis(u_{1i},v)+dis(u_{2i},v)+dis(u_{3i},v)\}}, min∑{dis(u1i,v)+dis(u2i,v)+dis(u3i,v)},其中 u 1 i ∈ L 1 , u 2 i ∈ L 2 , u 3 i ∈ L 3 , v u_{1i} \in L1, u_{2i} \in L2,u_{3i} \in L3, v u1i∈L1,u2i∈L2,u3i∈L3,v为树上任意点。
思考一下可以把上式转化为求 m i n ∑ { 1 2 ( d i s ( u 1 i , u 2 i ) + d i s ( u 2 i , u 3 i ) + d i s ( u 3 i , u 1 i ) ) } min\sum{\{\frac12(dis(u_{1i},u_{2i})+dis(u_{2i},u_{3i})+dis(u_{3i},u_{1i}))\}} min∑{21(dis(u1i,u2i)+dis(u2i,u3i)+dis(u3i,u1i))}。
如果对于每一组 d i s ( u 1 i , u 2 i ) dis(u_{1i},u_{2i}) dis(u1i,u2i)都求一次最短路那就铁炸了,因为数据范围也不能用floyd,我会的各种图论算法都搞不了。
这时候就得来点灵感了,考虑将三个标记点列表分成三张图。分别对每张图 L k Lk Lk运用换根DP的思想求出图上任一点 x x x到其他标记点的距离之和 d p [ L k ] [ x ] dp[Lk][x] dp[Lk][x],此时 d i s ( u 1 i , u 2 i ) dis(u_{1i},u_{2i}) dis(u1i,u2i)等于 ∑ d p [ L 2 ] [ u 1 i ] , u 1 i ∈ L 1 \sum dp[L2][u_{1i}],u_{1i} \in L1 ∑dp[L2][u1i],u1i∈L1。对于其他项做同样处理然后最后做个除法消去重复计算的边即可得出最终结果。
两个小坑:
- 部分地方会炸
long long
,需要及时进行除法运算避免溢出。 - 这题的递归比较深,
dfs
里参数太多可能爆栈。
AC代码:
#include <bits/stdc++.h>
using namespace std;
const int MAXN=200000+5;
typedef long long ll;
int child[MAXN];
struct node{
int to;
int w;
};
vector<node> g[MAXN];
ll *t_dp;
char *t_has;
int N;
void prev_dfs(int u,int fa){
for(node x:g[u]){
int v=x.to;
if(v==fa) continue;
prev_dfs(v,u);
t_dp[u]+=t_dp[v]+(1LL*child[v]+t_has[v])*x.w;
child[u]+=(child[v]+t_has[v]);
}
}
void next_dfs(int u,int fa,int fa_w){
if(u!=fa) t_dp[u]=t_dp[fa]+(1LL*N-2*child[u]-2*t_has[u])*fa_w;
for(node x:g[u]){
int v=x.to;
if(v==fa) continue;
next_dfs(v,u,x.w);
}
}
ll dp[3][MAXN];
char has[3][MAXN];
int cnt[3];
void init(int i){
memset(dp,0,sizeof(dp));
memset(has,0,sizeof(has));
}
int main(){
int n;
scanf("%d",&n);
for(int i=0;i<n-1;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
g[u].push_back(node{v,w});
g[v].push_back(node{u,w});
}
for(int k=0;k<3;k++){
memset(child,0,sizeof(child));
scanf("%d",&cnt[k]);
for(int i=0;i<cnt[k];i++){
int x;
scanf("%d",&x);
has[k][x]=1;
}
t_dp=dp[k];
t_has=has[k];
N=cnt[k];
prev_dfs(1,1);
next_dfs(1,1,0);
}
long double ans=0;
for(int k=0;k<3;k++){
for(int j=k+1;j<3;j++){
long double one=1.0;
for(int i=1;i<MAXN;i++){
if(has[k][i]){
ans+=one*dp[j][i]/(one*cnt[k]*cnt[j]);
}
}
}
}
printf("%.10Lf",ans/2.0);
return 0;
}
参考资料:
换根dp小结_a_forever_dream的博客-CSDN博客