CF123E Maze(期望dp,樹形dp,式子)
阿新 • • 發佈:2018-12-04
題目大意:
給你一棵樹,邊權都是1,每一個點有一個是起點的概率和一個是終點的概率,你將以起點為根,開始在樹上隨機dfs,每到一個點,就會將他的所有兒子隨機打亂成序列,然後按照那個隨機順序走完,直到走到終點。求dfs從起點到終點的期望長度。
其實一開始看到這個題,還是有點懵逼的啊
根據期望的線性性,我們可以通過求所有相鄰點的期望,然後直接相加,得到ans
那我們可以這麼考慮,對於一個點來說,假設我們要求的是從 ( 是 的兒子)的期望的話,如果走到一個錯的兒子,那麼就需要 步重新回來(相當於每條邊會走兩遍),而每個兒子在對應的 之前的概率又都是 (所有排列中,要不是y在前,就是那一個在前)
所以可以得知,每一個點的貢獻 就是
那麼我們可以通過列舉終點,然後算其他子樹的 以及概率和,求出來他們的貢獻
最後直接輸出ans就好
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define mk makr_pair
#define ll long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
const int maxn = 2e5+1e2;
const int maxm = 2*maxn;
int point[maxn],nxt[maxm],to[maxm];
double val[maxn];
int size[maxn];
double st[maxn],ed[maxn];
int n,m;
double sumst,sumed;
int cnt;
double ans;
void addedge(int x,int y)
{
nxt[++cnt]=point[x];
to[cnt]=y;
point[x]=cnt;
}
void dfs(int x,int fa)
{
size[x]=1;
val[x]=st[x];
//cout<<x<<" "<<val[x]<<endl;
for (int i=point[x];i;i=nxt[i])
{
int p = to[i];
if (p==fa) continue;
dfs(p,x);
size[x]+=size[p];
val[x]+=val[p];
}
}
int main()
{
n=read();
for (int i=1;i<n;i++)
{
int x=read(),y=read();
addedge(x,y);
addedge(y,x);
}
for (int i=1;i<=n;i++)
{
scanf("%lf%lf",&st[i],&ed[i]);
sumst+=st[i];
sumed+=ed[i];
}
for(int i=1;i<=n;i++)
{
st[i]=st[i]/sumst;
ed[i]=ed[i]/sumed;
// printf("%.4lf %.4lf\n",st[i],ed[i]);
}
dfs(1,0);
//cout<<val[1]<<endl;
for (int x=1;x<=n;x++)
{
for (int i=point[x];i;i=nxt[i])
{
int p =to[i];
if (size[p]>=size[x])
ans=ans+1.0*(1.0-val[x])*1.0*(1.0*n-size[x])*ed[x];
else
ans=ans+val[p]*1.0*size[p]*ed[x];
// cout<<x<<" "<<p<<" "<<ans<<endl;
}
}
printf("%.12lf",ans);
return 0;
}