浅谈期望与概率dp

1. 引入

A A A 开了一家抽奖店 , 中奖概率为 1 50 \frac{1}{50} 501 , 奖品是 100 100 100 元 , 每次抽奖需要 5 5 5 元 , 求收益的期望

1 50 × ( − 100 ) + 49 50 × 5 = 2.9 \frac{1}{50}\times (-100)+\frac{49}{50}\times 5=2.9 501×(100)+5049×5=2.9

这家店收益的期望为 + 2.9 +2.9 +2.9

2.期望 dp

2.1 一般的期望dp

例题1 : 百事世界杯之旅

f i f_i fi 表示已经集齐 i i i 个 , 还需要买个数的期望 , 那么 f n = 0 f_n=0 fn=0

当我们集齐 i i i 个时 , 有 n − i n \frac{n-i}{n} nni 概率买到新邮票 , 有 n i n \frac{ni}{n} nni 概率买到重复邮票

f i = n − i n × ( f i + 1 + 1 ) + i n × ( f i + 1 ) f_i=\frac{n-i}{n}\times (f_{i+1}+1)+\frac{i}{n} \times (f_i+1) fi=nni×(fi+1+1)+ni×(fi+1)

f i = n n − i + f i + 1 f_i=\frac{n}{n-i}+f_{i+1} fi=nin+fi+1

f 0 f_0 f0 即为最终答案

例题2 : 收集邮票
与上题一样 , 记 f i f_i fi 为已经集齐 i i i 个 , 还需要买个数的期望
g i g_i gi 为为已经集齐 i i i 个 , 还需要花钱的期望

f i = n n − i + f i + 1 f_i=\frac{n}{n-i}+f_{i+1} fi=nin+fi+1

假如每张邮票都是 1 1 1 块钱 , 那么 g i = n − i n × ( g i + 1 + 1 ) + i n × ( g i + 1 ) g_i=\frac{n-i}{n}\times (g_{i+1}+1)+\frac{i}{n} \times (g_i+1) gi=nni×(gi+1+1)+ni×(gi+1)

而题目要求第 k k k 张邮票 k k k 元 . 若在每张邮票 1 1 1 元的基础上 , 买第 x x x 张邮票使得第 x x x 张邮票以后的邮票都变贵一元 , 可以与第 k k k 张邮票 k k k 元达到相同效果 . 因此有 g i = n − i n × ( g i + 1 + f i ) + i n × ( g i + f i ) g_i=\frac{n-i}{n}\times (g_{i+1}+f_i)+\frac{i}{n} \times (g_i+f_i) gi=nni×(gi+1+fi)+ni×(gi+fi) (后面还要买 f i f_i fi 张邮票 , 共变贵 f i f_i fi 元)

g i = g i + 1 + n n − i × f i g_i=g_{i+1}+\frac{n}{n-i}\times f_i gi=gi+1+nin×fi

g 0 g_0 g0 即为最终答案

	cin >> n;
	for(int i=n-1;i>=0;i--)
		f[i] = f[i+1] + 1.0*n/(n-i),
		g[i] = g[i+1] + f[i]*n/(n-i);
	printf("%.2lf",g[0]);

例题3 : 爬树的甲壳虫

f i f_i fi 表示高度为 i i i 爬到树顶所需时间的期望

f i = ( 1 − P i + 1 ) × f i + 1 + P i + 1 × f 0 + 1 f_i=(1-P_{i+1})\times f_{i+1}+P_{i+1}\times f_0+1 fi=(1Pi+1)×fi+1+Pi+1×f0+1

推式子 :

f n = 0 f_n=0 fn=0

f n − 1 = ( 1 − P n ) f n + P n f 0 + 1 f_{n-1}=(1-P_n) f_n+P_nf_0+1 fn1=(1Pn)fn+Pnf0+1

f n − 2 = ( 1 − P n − 1 ) f n − 1 + P n − 1 f 0 + 1 f_{n-2}=(1-P_{n-1}) f_{n-1}+P_{n-1} f_0+1 fn2=(1Pn1)fn1+Pn1f0+1
= ( 1 − P n ) ( 1 − P n − 1 ) f n + ( P n + P n − 1 ) f 0 + 2 − P n − 1 =(1-P_n)(1-P_{n-1}) f_n+(P_n+P_{n-1}) f_0+2-P_{n-1} =(1Pn)(1Pn1)fn+(Pn+Pn1)f0+2Pn1

发现本质为 x f n + y f 0 + z x f_n+y f_0+z xfn+yf0+z

f i + 1 = x f n + y f 0 + z f_{i+1}=x f_n+y f_0+z fi+1=xfn+yf0+z

那么 f i = ( 1 − P i + 1 ) × ( x f n + y f 0 + z ) + P i + 1 × f 0 + 1 f_i=(1-P_{i+1})\times (x f_n+y f_0+z)+P_{i+1}\times f_0+1 fi=(1Pi+1)×(xfn+yf0+z)+Pi+1×f0+1

= ( x − x P i + 1 ) f n + ( y − y P i + 1 + P i + 1 ) f 0 + ( z − z P i + 1 + 1 ) =(x-xP_{i+1})f_n+(y-yP_{i+1}+P_{i+1})f_0+(z-zP_{i+1}+1) =(xxPi+1)fn+(yyPi+1+Pi+1)f0+(zzPi+1+1)

x ′ = x − x P i + 1 , x'=x-xP_{i+1}, x=xxPi+1,
y ′ = y − y P i + 1 + P i + 1 , y'=y-yP_{i+1}+P_{i+1}, y=yyPi+1+Pi+1,
z ′ = z − z P i + 1 + 1 z'=z-zP_{i+1}+1 z=zzPi+1+1

	int y=0, z=0;
	for(int i=n-1;i>=0;i--)
	{
		y = (y - y*p[i+1] + p[i+1] + mod) % mod;
		z = (z - z*p[i+1] + 1 + mod) % mod;
	}
	// f[0] = y*f[0] + z
	// (1-y)*f[0] = z;
	// f[0] = z/(1-y) 
	cout << (z*qpow(1-y,mod-2)+mod)%mod;

例题4:换教室

首先 floyd 预处理任意两点间最短路

memset(w,0x3f,sizeof(w));
	for(int i=1;i<=e;i++)
	{
		int x, y, z;
		cin >> x >> y >> z;
		w[x][y] = min(w[x][y], z), w[y][x] = w[x][y];
	}
	for(int k=1;k<=v;k++)
		for(int i=1;i<=v;i++)
			for(int j=1;j<=v;j++)
				 w[i][j] = min(w[i][j], w[i][k]+w[k][j]);

对于 i + 1 i+1 i+1 节课 , 会受到前面申请了几节课影响 , 会受到第 i i i 节课位置的影响 , 而我们只需知道是否换教室便可求出位置

所以状态设计是 f ( i , j , k ) f(i,j,k) f(i,j,k) 表示:前 i i i 节课 , 申请了 j j j 节课 , k k k 表示是否换教室

以转移 k = 0 k=0 k=0 ( 第 i i i 个不申请换教室为例)

f ( i , j , 0 ) = m i n { ( f ( i − 1 , j , 1 ) + w ( d [ i − 1 ] , c [ i ] ) ) ∗ k [ i − 1 ] + ( f ( i − 1 , j , 1 ) + w ( c [ i − 1 ] , c [ i ] ) ) ∗ ( 1 − k [ i − 1 ] ) = f ( i − 1 , j , 1 ) + w ( d [ i − 1 ] , c [ i ] ) ) ∗ k [ i − 1 ] + w ( c [ i − 1 ] , c [ i ] ) ) ∗ ( 1 − k [ i − 1 ] ) f ( i − 1 , j , 0 ) + w ( c [ i − 1 ] , c [ i ] ) f(i,j,0)=min\begin{cases} \small (f(i-1,j,1)+w(d[i-1],c[i]))*k[i-1]+(f(i-1,j,1)+w(c[i-1],c[i]))*(1-k[i-1])\\ =\small f(i-1,j,1)+w(d[i-1],c[i]))*k[i-1]+w(c[i-1],c[i]))*(1-k[i-1])\\ f(i-1,j,0)+w(c[i-1],c[i]) \end{cases} f(i,j,0)=min (f(i1,j,1)+w(d[i1],c[i]))k[i1]+(f(i1,j,1)+w(c[i1],c[i]))(1k[i1])=f(i1,j,1)+w(d[i1],c[i]))k[i1]+w(c[i1],c[i]))(1k[i1])f(i1,j,0)+w(c[i1],c[i])

然后就是很简单的 dp , 可以加滚动数组优化

for(int i=1;i<=n;i++)
		for(int j=0;j<=m;j++)
			f[i][j][1] = f[i][j][0] = inf;	
	f[1][1][1] = f[1][0][0] = 0;
	for(int i=2;i<=n;i++)
	{
		for(int j=0;j<=min(i,m);j++)
		{
		
			f[i][j][0] = min(f[i-1][j][1]+w[d[i-1]][c[i]]*k[i-1]+w[c[i-1]][c[i]]*(1-k[i-1]), f[i-1][j][0]+w[c[i-1]][c[i]]);
			if(j) f[i][j][1] = min(f[i-1][j-1][1]+w[d[i-1]][d[i]]*k[i-1]*k[i]+w[d[i-1]][c[i]]*k[i-1]*(1-k[i])+w[c[i-1]][c[i]]*(1-k[i-1])*(1-k[i])+w[c[i-1]][d[i]]*(1-k[i-1])*k[i],f[i-1][j-1][0]+w[c[i-1]][c[i]]*(1-k[i])+w[c[i-1]][d[i]]*k[i]);
		}
	} 
	double ans = inf;
	for(int j=0;j<=m;j++)
	{
		ans = min(ans, min(f[n][j][0], f[n][j][1]));
	}
	printf("%.2lf",ans);


2.2 图上的期望dp

例题5:绿豆蛙的归宿

f i f_i fi 表示 n → i n\to i ni 的期望

对于 u u u 的所有出边 u → v u\to v uv , f u = ∑ ( f v + w ( u , v ) i n d e g [ u ] ) \large f_u=\sum(\frac{f_v+w(u,v)}{indeg[u]}) fu=(indeg[u]fv+w(u,v))

f n = 0 f_n=0 fn=0

反向建图 , 拓扑排序

	while(!q.empty())
	{
		int u = q.front(); q.pop();
		for(auto edge:G[u])
		{
			int v = edge.to, w= edge.w;
			f[v] += (f[u]+w) / indeg2[v];
			indeg1[v]--;
			if(indeg1[v]==0) q.push(v);
		}
	}
	printf("%.2lf",f[1]);
}

例题6 : 游走

我们记以 i i i 为终点的所有路径数量为 c n t i cnt_i cnti , 记以 i i i 为终点的所有路径长度之和为 f i f_i fi

路径长度的期望应该等于 ∑ f i ∑ c n t i \large \frac{\sum f_i}{\sum cnt_i} cntifi

由于这是一张 D A G DAG DAG , 我们可按照拓扑续求 f i , c n t i f_i,cnt_i fi,cnti , 对于 v v v 的所有入边 u → v u\to v uv , c n t v = ∑ c n t u cnt_v=\sum cnt_u cntv=cntu , ( c n t i cnt_i cnti 初始为 1 1 1 ) , f v = ∑ ( f u + c n t u ) f_v=\sum (f_u+cnt_u) fv=(fu+cntu) ( 相当于所有到 u u u 的路径多走了 1 1 1 v v v , 一共多走了 c n t u cnt_u cntu)

	while(!q.empty())
	{
		int u = q.front(); q.pop();
		sum += cnt[u], tot += f[u], sum %= mod, tot %= mod;
		for(auto v : G[u])
		{
			cnt[v] += cnt[u], f[v] += f[u]+cnt[u], cnt[v] %= mod, f[v] %= mod;
			indeg[v]--;
			if(indeg[v]==0) q.push(v);
		}
	}

你可能感兴趣的:(学习笔记,题解,算法)