[解题笔记]期望

文章讲述了动态规划和记忆化搜索在解决期望值计算问题中的应用,提供了三个实例:红黑牌游戏、黑白球转换问题和NOIP2016的教室转换问题。每个问题都涉及到状态设计和概率计算,强调了正确理解题意和处理状态转移的重要性。
摘要由CSDN通过智能技术生成

总结

        关于期望,大多数题目都可采用动态规划或记忆化搜索解决。这种题目的难点就在于如何灵活地处理状态的定义于传递

一些题目

接下来分析一些做过的题目awa

1)红黑牌

你有一个包含R红色和B黑色牌的牌组。

你正在玩下面的游戏:你洗牌,然后开始逐个处理牌。对于你翻转的每张红牌,你得到一美元,而对于你翻转的每张黑卡,你必须支付1美元。在任何时候(包括比赛的开始),你都可以停下来并保留你的钱。

给你R和B,你最佳地玩这个游戏你将获得的金额的期望值。

输入格式

多组测试数据。

第一行,一个整数G,表示有G组测试数据。 1 <= G <= 10

每组测试数据格式: 

    第一行,两个整数,R和 B。 0 <=R,B <= 5000。

输出格式

共G行,共G行,每行一个实数,误差不超过0.0001。

样例

输入:

10

0 7

4 0

5 1

2 2

12 4

11 12

5000 5000

4950 4772

4446 4525

4446 4526

输出:

0.0

4.0

4.166666666666667

0.6666666666666666

8.324175824175823

1.075642825339958

36.90021846438633

191.15589434419024

8.13249058054577E-4

0.0

分析

这题的状态的设计与传递的大概构想很容易想出。

就dp[ i ][ j ]表示目前拿了i个红球,j个黑球的期望值,然后转移就从dp[ i - 1 ][ j ]或dp[ i ][ j - 1]来。

然而我在理解题意上就有偏差。题目讲到,在任何时候你都可以停下来保留你的钱,但没有说一定要在哪里保留。也就是说,整个过程没有期望值为负数的情况,最小为0,一旦出现哪种情况期望值为负数的,索性停止。

code

#include <bits/stdc++.h>
using namespace std;
int G,r,b;
double dp[5005][5005];
int main(){
    scanf("%d",&G);
    while(G--)
    {
        scanf("%d%d",&r,&b);
        dp[0][0] = 0;
        for(int i=1;i<=r;++i)dp[i][0]=i;
        for(int i=1;i<=b;++i)dp[0][i]=0;
        for(int i=1;i<=r;++i){
            for(int j=1;j<=b;++j){
                dp[i][j]=max( (dp[i-1][j] + 1) * i / (i+j)  
							+ (dp[i][j-1] - 1) * j / (i+j)
							, 0.0);
            }
        }
        printf("%lf\n",dp[r][b]);
    }
    return 0;
}

2)黑白球

        一个箱子里面有n个黑球m个白球。你每小时都随机从箱子里面抽出两个小球,然后把这两个球都染成黑球,然后再放回去。问需要多少小时才能把所有小球变成黑色小球?输出期望值。

输入格式

 第一行,一个整数G,表示有G组测试数据。1 <= G <= 10

 每组测试数据格式如下:

  一行,两个整数,n和m。1 <=n,m<=47。

输出格式

共G行,每行一个实数。误差不能超过0.00001。

样例

输入:

5

1 1

2 1

1 2

4 7

1 3

输出:

1.0

1.5

2.0

13.831068977298521

3.4

分析

        直觉告诉我设状态设dp[ i ][ j ],但这道题中白球终究变为黑球,所以直接设dp[ i ]为有i个黑球时的期望次数。

        这道题容易疏忽的地方:每次拿两个时,有黑黑、黑白、白白三种颜色搭配情况,但是注意,黑白搭配的概率是黑黑、白白的两倍!

code

#include<bits/stdc++.h>
using namespace std;
int G;
double dp[100];
int N,n,m;
int main(){
	scanf("%d",&G);
	while(G--){
		scanf("%d%d",&n,&m);
		double Tot=(n+m)*(n+m-1);
		memset(dp,0,sizeof(dp));
		for(int i=n+m-1;i>=n;--i){
			int j=n+m-i;
			double t1=(dp[i+2]+1.0)*double(j)*double(j-1)/Tot;
			double t2=(dp[i+1]+1.0)*double(i)*double(j)/Tot;
			double t3=double(i)*double(i-1)/Tot;
			t2*=2.0;
			dp[i]=(t1+t2+t3)/(1.0-t3);
		}
		printf("%lf\n",dp[n]);
	}
	return 0;
}

3)NOIP2016tg换教室

分析

这题把最短路和期望两个板块绑在了一块,主要难点集中在期望。

不难想出定义dp[ i ][ j ][ k(bool类型) ]为到了第i节课,用了j次申请,是在c教室还是d教室

于是便有了一大坨的转移代码,不多说了、

code

#include<bits/stdc++.h>
using namespace std;
int n,m,V,E;
double dp[2001][2001][2],k[2001];
int dis[301][301],c[2001],d[2001];
int main(){
	scanf("%d%d%d%d",&n,&m,&V,&E);
	for(int i=1;i<=n;++i)scanf("%d",&c[i]);
	for(int i=1;i<=n;++i)scanf("%d",&d[i]);
	for(int i=1;i<=n;++i)scanf("%lf",&k[i]);
	///
	memset(dis,63,sizeof(dis));
	while(E--){
		int t1,t2,t3;
		scanf("%d%d%d",&t1,&t2,&t3);
		dis[t1][t2]=min(dis[t1][t2],t3);
		dis[t2][t1]=min(dis[t2][t1],t3);
	}
	for(int l=1;l<=V;++l)
		for(int i=1;i<=V;++i)
			for(int j=1;j<=V;++j)
				dis[i][j]=min(dis[i][j],dis[i][l]+dis[l][j]);
	for(int i=1;i<=V;++i)dis[i][i]=0;//注意要加上这句话qwq
	///
	for(int i=0;i<=n;++i)
		for(int j=0;j<=m;++j)
			dp[i][j][0]=dp[i][j][1]=2100000000;
	dp[1][0][0]=dp[1][1][1]=0;
	for(int i=2;i<=n;++i){
		int c1=dis[c[i-1]][c[i]],c2=dis[c[i-1]][d[i]];
		int c3=dis[d[i-1]][c[i]],c4=dis[d[i-1]][d[i]];
		for(int j=min(m,i);j;--j){
			dp[i][j][1]=min(
				dp[i-1][j-1][0]+c1*(1-k[i])+c2*k[i],
				dp[i-1][j-1][1]+c1*(1-k[i-1])*(1-k[i])+c2*(1-k[i-1])*k[i]+
								c3*  k[i-1]  *(1-k[i])+c4*  k[i-1]  *k[i]
			);
			dp[i][j][0]=min(
				dp[i-1][j][0]+c1,
				dp[i-1][j][1]+c1*(1-k[i-1])+c3*k[i-1]
			);
		}
		dp[i][0][0]=dp[i-1][0][0]+c1;
	}
	double ans=dp[n][0][0];
	for(int i=1;i<=m;++i){
		ans=min(ans,min(dp[n][i][0],dp[n][i][1]));
	}
	printf("%.2lf",ans);
	return 0;
}

由于我比较懒,博客里就写这么多吧qwq

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值