2020CCPC威海 C Rencontre(树形DP,期望)
题意:
有3个人,每个人有一些待选位置。
就是当确定三个人确定位置 u1 , u2 , u3 后,需要找到一个位置 v 到三个位置的距离之和最小,
现在给出 u1 , u2 , u3 的待选取值,问 距离之和的期望是多少。
思路:
模拟一下可以发现,3人回合的距离和为
我们按照边,对于 分别统计贡献。
则最终期望就是
现在问题就是如何快速求出 了
DP思想:计算每条边的贡献。
具体就是:
对于一条边 来说,当移除掉这条边后,整棵树将会被分成不连通的两个部分,记为 T1 和 T2,比较显然的是:
- T1 中的 u1 到 T2 中的 u2 必然会经过当前边
- T1 中的 u2 到 T2 中的 u1 必然会经过当前边
直接树形 dp 就好了
代码
#include<bits/stdc++.h> using namespace std; #define int long long #define pii pair<int,int> const int N=5e5+10; int siz[4][N],cnt[4]; vector<pii> g[N]; void dfs1(int u,int fa){ for(int i=0;i<g[u].size();i++){ int v=g[u][i].second; int w=g[u][i].first; if(v==fa) continue; dfs1(v,u); for(int i=1;i<=3;i++) siz[i][u]+=siz[i][v]; } } double ans=0; void dfs2(int u,int fa){ for(int i=0;i<g[u].size();i++){ int v=g[u][i].second; int w=g[u][i].first; if(v==fa) continue; dfs2(v,u); for(int i=1;i<=3;i++){ for(int j=1;j<=3;j++){ if(i==j)continue; double temp=1.0*(cnt[i]-siz[i][v])*(siz[j][v])*1.0*w; temp=temp/(cnt[i]*cnt[j]*2.0); ans+=temp; } } } } signed main() { cin.tie(); std::ios::sync_with_stdio(false); int n;cin>>n; for(int i=0;i<n-1;i++){ int u,v,w; cin>>u>>v>>w; g[u].push_back({w,v}); g[v].push_back({w,u}); } for(int i=1;i<=3;i++){ cin>>cnt[i]; for(int j=1;j<=cnt[i];j++){ int t;cin>>t; siz[i][t]++; } } dfs1(1,-1); dfs2(1,-1); printf("%.10f\n",ans); return 0; }
原文1链接:https://blog.csdn.net/zstuyyyyccccbbbb/article/details/109374514
原文2链接:https://blog.csdn.net/tomjobs/article/details/109384974
本文作者:kingwzun
本文链接:https://www.cnblogs.com/kingwz/p/16809876.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
2021-10-20 接口(interface)