[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++

原文地址:https://www.cnblogs.com/wzc521/p/11331681.html