1. 程式人生 > >CF123E Maze(期望dp,樹形dp,式子)

CF123E Maze(期望dp,樹形dp,式子)

題目連結

題目大意:
給你一棵樹,邊權都是1,每一個點有一個是起點的概率和一個是終點的概率,你將以起點為根,開始在樹上隨機dfs,每到一個點,就會將他的所有兒子隨機打亂成序列,然後按照那個隨機順序走完,直到走到終點。求dfs從起點到終點的期望長度。

其實一開始看到這個題,還是有點懵逼的啊

根據期望的線性性,我們可以通過求所有相鄰點的期望,然後直接相加,得到ans

那我們可以這麼考慮,對於一個點來說,假設我們要求的是從 x

> y x->y y y x x
的兒子)的期望的話,如果走到一個錯的兒子,那麼就需要 2 s i z e [ s o
n ] 2*size[son]
步重新回來(相當於每條邊會走兩遍),而每個兒子在對應的 y y 之前的概率又都是 1 2 \frac{1}{2} (所有排列中,要不是y在前,就是那一個在前)

所以可以得知,每一個點的貢獻 就是 s i z e [ x ] size[x]

那麼我們可以通過列舉終點,然後算其他子樹的 s i z e [ x ] size[x] 以及概率和,求出來他們的貢獻

最後直接輸出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;
}