首页 > 代码库 > ZOJ 3329 - One Person Game
ZOJ 3329 - One Person Game
题意:每次筛三个骰子面分别为k1,k2,k3,如果三个骰子的值分别为a,b,c则得分置0,否则得到分数加上三个骰子的值的和,如果得分大于等于n则结束游戏。
设E[i]表示当前得到i分时结束游戏的期望。
则E[i]=sum{Pk*(E[i+k]+1)|k为三个骰子可能取得的分数且不包括a,b,c这种情况}+1/(k1*k2*k3)(E[0]+1)
=sum{Pk*(E[i+k])}+1/(k1*k2*k3)*E[0]+1
这里出现了一个问题,之前的方程都是只与一个方向的有关,而这里E[i]与E[0]和E[i+k]有关, E[0]是E[i]的先前结点,而E[i+k]是E[i]的后置结点,因此无法使用DP解决这个问题。我们考虑消去一个变量,这里只有最后的结点E[n]是已知的,所以我们可以消去后置结点E[i+k]。这样假设E[i]=A[i]*E[0]+B[i],代入E[i+k],可得E[i]=sum{Pk*(A[i+k]*E[0]+B[i+k])}+1/(k1*k2*k3)*E[0]+1,进一步得E[i]=(sum{Pk*A[i+k]}+1/(k1*k2*k3))*E[0]+sum{Pk}*B[i+k]+1。
这样对应系数可得到A[i]=sum{Pk*A[i+k]}+1/(k1*k2*k3),B[i]=sum{Pk}*B[i+k]+1。
我们知道E[n]=0,所以A[n]=0,B[n]=0。
这样可以递推求出所有A[i]和B[i],这样也就能算出所有的E[i]了。
最终答案是E[0]。E[0]=A[0]*E[0]+B[0],所以E[0]=B[0]/(1-A[0])。
#include <iostream> #include <cstdio> #include <cstring> #include <vector> #include <queue> #include <algorithm> #define ll long long #define MAXN 30005 using namespace std; double A[525],B[525]; double pro[30]; int main() { int T; scanf("%d",&T); while(T--) { int n,k1,k2,k3,a,b,c; scanf("%d%d%d%d%d%d%d",&n,&k1,&k2,&k3,&a,&b,&c); double r=1.0/(k1*k2*k3); memset(A,0,sizeof(A)); memset(B,0,sizeof(B)); memset(pro,0,sizeof(pro)); for(int i=1; i<=k1; ++i) for(int j=1; j<=k2; ++j) for(int k=1; k<=k3; ++k) if(!(i==a&&j==b&&k==c)) pro[i+j+k]+=r; int s=k1+k2+k3; for(int i=n; i>=0; --i) { for(int j=3; j<=s; ++j) { A[i]+=pro[j]*A[i+j]; B[i]+=pro[j]*B[i+j]; } A[i]+=r; B[i]++; } printf("%.8f\n",B[0]/(1-A[0])); } return 0; }
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。