zoj 3329 One Person Game(有环的概率dp)

来源:互联网 发布:php销售管理系统 编辑:程序博客网 时间:2024/05/22 08:12

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3754


开始看错题意了,以为没翻到a,b,c时要在原来的基础上加a+b+c,按我的意思推出来一个公式,没想到样例还过了,简直无法debug。


公式很好推,设dp[i]表示当前为i分时到达目标状态需要投掷的期望,可转移到两个状态dp[0]和dp[i+k]。设转移到dp[0]

的概率是p0,转移到dp[i+k]的概率是pk。那么可得dp[i] = p0*dp[0] + pk*dp[i+k] + 1。发现所有的dp[i]都与dp[0]有关。

下面的推导参考:http://www.cnblogs.com/kuangbin/archive/2012/10/03/2710648.html

设dp[i]=A[i]*dp[0]+B[i];代入上述方程右边得到:dp[i]=∑(pk*A[i+k]*dp[0]+pk*B[i+k])+dp[0]*p0+1     =(∑(pk*A[i+k])+p0)dp[0]+∑(pk*B[i+k])+1;     明显A[i]=(∑(pk*A[i+k])+p0)     B[i]=∑(pk*B[i+k])+1     先递推求得A[0]和B[0].     那么  dp[0]=B[0]/(1-A[0]);

然后逆推出A[0]和B[0]。

#include <stdio.h>#include <iostream>#include <map>#include <set>#include <list>#include <stack>#include <vector>#include <math.h>#include <string.h>#include <queue>#include <string>#include <stdlib.h>#include <algorithm>//#define LL __int64#define LL long long#define eps 1e-8#define PI acos(-1.0)using namespace std;const int INF = 0x3f3f3f3f;const int maxn = 4010;double dp[10010];double A[600],B[600];double p[100];int main(){int test;int n,a,b,c;int k1,k2,k3;scanf("%d",&test);while(test--){scanf("%d %d %d %d %d %d %d",&n,&k1,&k2,&k3,&a,&b,&c);double p0 = 1.0/(k1*k2*k3);memset(p,0,sizeof(p));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)                        p[i+j+k] += p0;        }    }}memset(A,0,sizeof(A));memset(B,0,sizeof(B));for(int i = n; i >= 0; i--){    A[i] = p0,B[i] = 1;    for(int j = 1; j <= k1+k2+k3; j++)    {        A[i] += p[j]*A[i+j];        B[i] += p[j]*B[i+j];    }}printf("%.15lf\n",B[0]/(1-A[0]));}return 0;}



0 0