• 配对游戏(概率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
    ",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
    ",ans[n]);
        return 0;
    }
    

      

  • 相关阅读:
    Qt中widget重新setParent需要注意的问题
    在有状态机下,写自动测试需要注意的问题
    C#获取当前路径的7种方法
    VS快捷键大全
    [WPF]设置背景色
    [WPF]建立自适应窗口大小布局的WinForm窗口
    [WPF]Slider控件常用方法
    [C#.NET]
    VB中的API详解
    VB6.0和VB.Net的函数等对照表
  • 原文地址:https://www.cnblogs.com/Zhi-71/p/12153392.html
Copyright © 2020-2023  润新知