bzoj_2318_Spoj4060 game with probability Problem

首先要理解题意

题意是说Alice和Bob能投出他们想要的那一面的p和q,不是只能投出1...

也就是说他们可以根据场上情况来决策p/q的概率来投出1还是0

我们来倒着定义状态数组,逆推

$f_i$表示场上还有i颗石子,在这一轮Alice先手赢的概率

$g_i$表示场上还有i颗石子,在这一轮Alice后手赢的概率

"这一轮"的意思是当前一直没人投出1,一旦有人投出1,这一轮结束

(1)当$f_{i-1}>g_{i-1}$时

Alice希望这一轮Bob拿到石子,这样她在下一轮才能先手,所以Alice在这一轮不想拿,Bob也不想拿

当Alice先手时,$f_i=g_{i-1}*(1-p)+g_i*p$

当Alice后手时,$g_i=f_{i-1}*(1-q)+f_i*q$

由于他们都不想拿,所以p/q都表示他们投出0

这样就好理解了

(2)当$f_{i-1}<g_{i-1}$时

与(1)差不多

$f_i=g_{i-1}*p+g_i*(1-p)$

$g_i=f_{i-1}*q+f_i*(1-q)$

然后经过代入化简,就可以线性递推了

然后n很大,但是当n到一定程度后,概率就会趋近于某个值,对于1e-6的精度,n推到1e4就足够了

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <iostream>
#include <vector>
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
#define rint register int
#define dd double
using namespace std;
inline void read(int &x)
{
    x=0; char q=getchar();
    while(q<'0'||q>'9') q=getchar();
    while(q>='0'&&q<='9') x=x*10+q-'0',q=getchar();
}

int T;
int n;
dd p,q,g[10006],f[10006];

int main(){
    
    //freopen("in.in","r",stdin);
    
    rint i;
    
    read(T);
    while(T--)
    {
        read(n); scanf("%lf%lf",&p,&q);
        n=min(n,10000);
        f[0]=0; g[0]=1.0;
        for(i=1;i<=n;++i)
        {
            if(f[i-1]>g[i-1])
            {
                f[i]=((1.0-p)*g[i-1]+p*(1.0-q)*f[i-1])/(1.0-p*q);
                g[i]=((1.0-q)*f[i-1]+q*(1.0-p)*g[i-1])/(1.0-p*q);
            }
            else
            {
                f[i]=(p*g[i-1]+q*(1.0-p)*f[i-1])/(1.0-(1.0-p)*(1.0-q));
                g[i]=(q*f[i-1]+p*(1.0-q)*g[i-1])/(1.0-(1.0-p)*(1.0-q));
            }
        }
        printf("%.6lf\n",f[n]);
    }
}
A

 

posted @ 2017-10-29 20:48  A_LEAF  阅读(190)  评论(0编辑  收藏  举报