配对游戏(概率DP)
链接:https://ac.nowcoder.com/acm/problem/13333
来源:牛客网
题目描述
美团点评是综合性生活服务平台,覆盖吃喝玩乐。在休闲娱乐版块,有很多轰趴、桌游、密室逃脱类的项目,适合多人一起玩。下面就是出自团队游戏场景中的一个问题。
有 n 个人排成一排,一开始全部面向前方,然后大家一起转身,随机朝左或是朝右转。
转身后,不断检查队列,如果存在两个面对面的相邻的人,则将这两个人从队列中消除;直到不存在两个面对面的相邻的人。
例如 > 表示向右, < 表示向左
队列“>>><<<”的消除过程为,“>>><<<”到“>><<”到“><”到“”(每次去除一对),最后剩下人数为0。
队列“>><><<<>”的消除过程为,“>><><<<>”到“>><<<>”到“><<>”到“<>”(每次去除一对),最后剩下人数为2
求最后剩下人数的期望值。
有 n 个人排成一排,一开始全部面向前方,然后大家一起转身,随机朝左或是朝右转。
转身后,不断检查队列,如果存在两个面对面的相邻的人,则将这两个人从队列中消除;直到不存在两个面对面的相邻的人。
例如 > 表示向右, < 表示向左
队列“>>><<<”的消除过程为,“>>><<<”到“>><<”到“><”到“”(每次去除一对),最后剩下人数为0。
队列“>><><<<>”的消除过程为,“>><><<<>”到“>><<<>”到“><<>”到“<>”(每次去除一对),最后剩下人数为2
求最后剩下人数的期望值。
输入描述:
一行一个正整数 n (1 ≤ n ≤ 2000)。
输出描述:
一行一个实数,表示剩下人数的期望值,四舍五入保留三位小数。
示例1
输出
复制4.168
这里提供两种解题思路(见代码)
#include<bits/stdc++.h> using namespace std; const int maxn=2005; double dp[maxn][maxn];//前i个人还有j个人向右消除了的期望数 double dp1[maxn][maxn];//达到dp[i][j]的概率 /* 考虑第i个人: 如果他向右那么dp[i][j+1] += dp[i-1][j]/2 dp1[i][j+1] += dp1[i-1][j]/2 如果他向左那么dp[i][j-1] += dp[i-1][j]/2 + dp1[i-1][j] dp1[i][j-1] += dp1[i-1][j]/2 注意j为0的时候 */ const double tem=0.5; double ans[maxn]; int main(){ dp1[0][0]=1; for(int i=1;i<maxn;i++){ for(int j=0;j<i;j++){ dp[i][j+1] += dp[i-1][j]*tem; dp1[i][j+1] += dp1[i-1][j]*tem; if(j>0){ dp[i][j-1] += dp[i-1][j]*tem+dp1[i-1][j]; dp1[i][j-1] += dp1[i-1][j]*tem; } else{ dp[i][j] += dp[i-1][j]/2; dp1[i][j] += dp1[i-1][j]/2; } } } for(int i=1;i<maxn;i++){ ans[i]=i; for(int j=0;j<=i;j++){ ans[i]-=dp[i][j]; } } int n; while(scanf("%d",&n)!=EOF) printf("%.3lf\n",ans[n]); return 0; }
#include<bits/stdc++.h> using namespace std; const int maxn=2005; double dp[maxn][maxn];//前i个人还有j个人向右剩下的期望数 double dp1[maxn][maxn];//达到dp[i][j]的概率 /* 考虑第i个人: 如果他向右那么dp[i][j+1] += dp[i-1][j]/2+dp1[i-1][j] dp1[i][j+1] += dp1[i-1][j]/2 如果他向左那么dp[i][j-1] += dp[i-1][j]/2 - dp1[i-1][j] dp1[i][j-1] += dp1[i-1][j]/2 注意j为0的时候 */ const double tem=0.5; double ans[maxn]; int main(){ dp1[0][0]=1; for(int i=1;i<maxn;i++){ for(int j=0;j<i;j++){ dp[i][j+1] += dp[i-1][j]*tem + dp1[i-1][j]; dp1[i][j+1] += dp1[i-1][j]*tem; if(j>0){ dp[i][j-1] += dp[i-1][j]*tem - dp1[i-1][j]; dp1[i][j-1] += dp1[i-1][j]*tem; } else{ dp[i][j] += dp[i-1][j]/2; dp1[i][j] += dp1[i-1][j]/2; } } } for(int i = 1;i < maxn; i++){ for(int j = 0;j <= i;j++){ ans[i] += dp[i][j]; } } int n; while(scanf("%d",&n)!=EOF) printf("%.3lf\n",ans[n]); return 0; }