TopCoder

TopCoder - 12349 SRM579 Round1 Div1 RockPaperScissors (概率dp)

题目大意:

(n)个骰子,每个骰子有300个面,其中有(a_i,b_i,c_i)分别为石头/布/剪刀

每轮你选择出石头/剪刀/布,然后会从剩下的骰子中随机取一个再随机结果,但是你不知道取的是什么骰子

赢一局的权值为3,平局为1

求最优情况下最大的权值期望

[ ]

题目分析:

显然当前的局面只和已经抽出的石头/布/剪刀的数量有关(因为这是你唯一的决策依据,也是唯一影响局面的)

乍一看非常抽象的决策过程,实在无法通过分析得到每一种局面下应该作出的决策

于是考虑能否直接把每一种局面出现的概率求出,决策后将期望线性相加

不妨把随机取出的骰子放在一个序列上,一个局面是由已经出现的骰子和当前第(i)次决策的骰子组成的

(dp_{i,j,k,typ})表示已经出现的骰子中出现(i,j,k)个石头/布/剪刀,当前决策时骰子结果为(typ)的概率

实际在(dp)时,(typ)一维需要额外加入一个值表示未确定下一个是什么

考虑对于每个骰子,枚举它是已经出现/正在决策/在第(i)次决策之后出现,将其概率累和

(dp)状态为(O(n^3)),转移次数为(O(n)),复杂度为(O(n^4))

最后对于每种局面计算最优的决策即可

#include<bits/stdc++.h>
using namespace std;

#define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i)
template <class T> inline void cmin(T &a,T b){ ((a>b)&&(a=b)); }
template <class T> inline void cmax(T &a,T b){ ((a<b)&&(a=b)); }

class RockPaperScissors {
private:
	static const int N=53;
	static const int eps=1e-9;
	double F[N][N][N][4],G[N][N][N][4],w[3];
	double C[N][N];

public:
	
	double bestScore(vector <int> w1, vector <int> w2, vector <int> w3) {
		int n=w1.size();
		rep(i,0,n) rep(j,C[i][0]=1,i) C[i][j]=C[i-1][j-1]+C[i-1][j];
		memset(F,0,sizeof F),F[0][0][0][3]=1;
		rep(i,1,n) {
			w[0]=w1[i-1]/300.0; w[1]=w2[i-1]/300.0; w[2]=w3[i-1]/300.0;
			rep(a,0,i) rep(b,0,i-a) rep(c,0,i-a-b) rep(d,0,3) G[a][b][c][d]=F[a][b][c][d];
			rep(a,0,i) rep(b,0,i-a) rep(c,0,i-a-b) rep(d,0,3) if(G[a][b][c][d]>eps) {
				// 枚举这个骰子在之前出现过了
				F[a+1][b][c][d]+=G[a][b][c][d]*w[0];
				F[a][b+1][c][d]+=G[a][b][c][d]*w[1];
				F[a][b][c+1][d]+=G[a][b][c][d]*w[2];
				// 枚举这个骰子为下一个出现的
				if(d==3) rep(e,0,2) F[a][b][c][e]+=G[a][b][c][d]*w[e];
			}
		}
		double ans=0;
		rep(a,0,n-1) rep(b,0,n-1-a) rep(c,0,n-1-a-b) {
			// 决策这一轮出什么
			double ma=0;
			rep(d,0,2) cmax(ma,F[a][b][c][d]+F[a][b][c][(d+2)%3]*3);
			ans+=ma/C[n][a+b+c]/(n-a-b-c);
		}
		return ans;
	}
};
原文地址:https://www.cnblogs.com/chasedeath/p/14056819.html