zoukankan      html  css  js  c++  java
  • [CSP-S模拟测试]:石头剪刀布(rps)(概率DP)

    题目传送门(内部题9)


    输入格式

    第一行一个整数$n$。接下来$n$行每行$3$个非负整数$r_i,p_i,s_i$。


    输出格式

    一行一个实数表示答案。当你的答案与标准答案的绝对或相对误差不超过${10}^{-9}$时判为正确。


    样例

    样例输入:

    3
    300 0 0
    0 300 0
    0 0 300

    样例输出:

    6.333333333333


    数据范围与提示

    对于$10%$的数据,$n=1$。
    对于$30%$的数据,$nleqslant 10$。
    对于另外$10%$的数据,所有$r_i$均相等,所有$p_i$均相等。
    对于又另外$30%$的数据,$r_i=0$。
    对于$100%$的数据,$1leqslant nleqslant 50$,$r_i+p_i+s_i=300$。


    题解

    首先,这道题是一道假期望。

    用$g[i][j][k]$表示第$i+j+k$轮出了$i$个石头,$j$个剪刀,$k$个布的概率。

    用$dp[i][j][k][l]$表示前$i+j+k$轮出了$i$个石头,$j$个剪刀,$k$个布的概率。

    注意我们不是在$dp[i][j][k][x]$中取$max$,而是在$dp[i][j][k][x]+dp[i][j][k][x+1] imes 3$中取$max$。

    $g[i][j][k]$也非常好求,直接给出式子:$g[i][j][k]=g[i-1][j][k] imes r[t]+g[i][j-1][k] imes s[t]+g[i][j][k-1] imes p[t]$。

    注意$dp$和$g$的意义,所以对$g$的转移需要在$dp$之后。

    还有就是注意输入顺序是:石头、布、剪刀,即可。

    时间复杂度:$Theta(n^4)$。

    期望的分:$100$分。

    实际的分:$100$分。


    代码时刻

    #include<bits/stdc++.h>
    using namespace std;
    int n;
    long double w[100],z[100],c[100];
    long double C[51][51];
    long double g[51][51][51],dp1[51][51][51],dp2[51][51][51],dp3[51][51][51];
    long double ans;
    int main()
    {
    	scanf("%d",&n);
    	for(int i=0;i<=n;i++)
    	{
    		C[i][0]=1.0;
    		for(int j=1;j<=i;j++)
    			C[i][j]=C[i-1][j]+C[i-1][j-1];
    	}
    	for(int i=1;i<=n;i++)
    	{
    		cin>>w[i]>>c[i]>>z[i];//注意输入顺序
    		w[i]/=300.0;
    		z[i]/=300.0;
    		c[i]/=300.0;
    	}
    	g[0][0][0]=1.0;
    	for(int t=1;t<=n;t++)
    		for(int i=t;~i;i--)
    			for(int j=t-i;~j;j--)
    				for(int k=t-i-j;~k;k--)
    				{
    					if(i+j+k!=t)
    					{
    						if(i)dp1[i][j][k]+=dp1[i-1][j][k]*w[t];
    						if(j)dp1[i][j][k]+=dp1[i][j-1][k]*z[t];
    						if(k)dp1[i][j][k]+=dp1[i][j][k-1]*c[t];
    						dp1[i][j][k]+=g[i][j][k]*w[t];
    						if(i)dp2[i][j][k]+=dp2[i-1][j][k]*w[t];
    						if(j)dp2[i][j][k]+=dp2[i][j-1][k]*z[t];
    						if(k)dp2[i][j][k]+=dp2[i][j][k-1]*c[t];
    						dp2[i][j][k]+=g[i][j][k]*z[t];
    						if(i)dp3[i][j][k]+=dp3[i-1][j][k]*w[t];
    						if(j)dp3[i][j][k]+=dp3[i][j-1][k]*z[t];
    						if(k)dp3[i][j][k]+=dp3[i][j][k-1]*c[t];
    						dp3[i][j][k]+=g[i][j][k]*c[t];
    					}
    					if(i)g[i][j][k]+=g[i-1][j][k]*w[t];
    					if(j)g[i][j][k]+=g[i][j-1][k]*z[t];
    					if(k)g[i][j][k]+=g[i][j][k-1]*c[t];
    				}
    	for(int i=0;i<n;i++)
    		for(int j=0;i+j<n;j++)
    			for(int k=0;i+j+k<n;k++)
    				ans+=max(dp1[i][j][k]+3.0*dp2[i][j][k],max(dp2[i][j][k]+3.0*dp3[i][j][k],dp3[i][j][k]+3.0*dp1[i][j][k]))/(C[n][i+j+k]*(n-i-j-k));
    	cout<<fixed<<setprecision(12)<<ans<<endl;
    	return 0;
    }
    

    rp++

  • 相关阅读:
    Dp~Hrbust1426( 集训队的晚餐 )
    DP~数塔(hrbustoj1004)
    MyEclipse启动性能优化(----加快启动速度)
    很实用的php的缓存类文件示例
    PHP中9大缓存技术总结
    微信公众平台开发(76) 获取用户基本信息
    js中 onreadystatechange 和 onload的区别
    一个js文件导入js的函数
    PHP cURL实现模拟登录与采集使用方法详解教程
    Mysql清空表(truncate)与删除表中数据(delete)的区别
  • 原文地址:https://www.cnblogs.com/wzc521/p/11331681.html
Copyright © 2011-2022 走看看