配对游戏(概率DP)

链接:https://ac.nowcoder.com/acm/problem/13333
来源:牛客网

题目描述

美团点评是综合性生活服务平台,覆盖吃喝玩乐。在休闲娱乐版块,有很多轰趴、桌游、密室逃脱类的项目,适合多人一起玩。下面就是出自团队游戏场景中的一个问题。
有 n 个人排成一排,一开始全部面向前方,然后大家一起转身,随机朝左或是朝右转。
转身后,不断检查队列,如果存在两个面对面的相邻的人,则将这两个人从队列中消除;直到不存在两个面对面的相邻的人。
例如 > 表示向右, < 表示向左
队列“>>><<<”的消除过程为,“>>><<<”到“>><<”到“><”到“”(每次去除一对),最后剩下人数为0。
队列“>><><<<>”的消除过程为,“>><><<<>”到“>><<<>”到“><<>”到“<>”(每次去除一对),最后剩下人数为2
求最后剩下人数的期望值。

输入描述:

一行一个正整数 n (1 ≤ n ≤ 2000)。

输出描述:

一行一个实数,表示剩下人数的期望值,四舍五入保留三位小数。
示例1

输入

复制
10

输出

复制
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;
}

  

posted @ 2020-01-05 19:49  风雨兼程-zhi  阅读(423)  评论(0编辑  收藏  举报