[题解] BZOJ 2318 Spoj4060 game with probability Problem

BZOJ 2318 Spoj4060 game with probability Problem

题目描述 Description
Alice和Bob在玩一个游戏。有n个石子在这里,Alice和Bob轮流投掷硬币,如果正面朝上,则从n个石子中取出一个石子,否则不做任何事。取到最后一颗石子的人胜利。Alice在投掷硬币时有p的概率投掷出他想投的一面,同样,Bob有q的概率投掷出他相投的一面。

输入描述 Input Description
第一行一个正整数t,表示数据组数。

对于每组数据,一行三个数n,p,q。

输出描述 Output Description
对于每组数据输出一行一个实数,表示Alice胜利的概率,保留6位小数。

样例输入 Sample Input
1
1 0.5 0.5

样例输出 Sample Output
0.666667

数据范围及提示 Data Size & Hint
1 <= t <= 50 , 0.5 <= p , q <= 0.99999999 , 1 <= n <= 99999999

Solution

f [ i ] 为还剩 i 个石子时轮到Alice,Alice的胜率, g [ i ] 为还剩 i 个石子时轮到Bob,Alice的胜率
假设每一次都是拿走石头最优,则会有
f [ i ] = p g [ i 1 ] + ( 1 p ) g [ i ]
g [ i ] = q f [ i 1 ] + ( 1 q ) f [ i ]
将两式化为可以递推的形式,使 f [ i ] f [ i 1 ] g [ i 1 ] 转移, g [ i ] 同理
最终化为:

f [ i ] = p g [ i 1 ] + ( 1 p ) q f [ i 1 ] p + q p q

g [ i ] = q f [ i 1 ] + ( 1 q ) p g [ i 1 ] p + q p q

好的,但是有个问题,就是并不一定每次都是拿走石头最优,万一这次拿走石头后对方马上就赢了呢?
所以说有时候可能会选择不拿走石子
不拿走石子时则会有:
f [ i ] = p g [ i ] + ( 1 p ) g [ i 1 ]
g [ i ] = q f [ i ] + ( 1 q ) f [ i 1 ]

忽然发现不就把 ( p , 1 p ) , ( q , 1 q ) 分别对调一下么

扫描二维码关注公众号,回复: 1425835 查看本文章

什么时候拿走石头最优呢?若成功拿走石子的收益大于不拿走石子的收益者拿走,否则不拿走
对比 f [ i 1 ] , g [ i 1 ] 即可

代码如下:

#include <bits/stdc++.h>
using namespace std;
int n;
double p,q;
double f[10005],g[10005];
void work() {
    scanf("%d%lf%lf",&n,&p,&q);
    n=min(n,10000);
    g[0]=1;
    for(int i=1;i<=n;i++) {
        if(f[i-1]>g[i-1]) { p=1.0-p;q=1.0-q; }
        double d=p+q-p*q;
        f[i]=(p*g[i-1]+(1-p)*q*f[i-1])/d;
        g[i]=(q*f[i-1]+(1-q)*p*g[i-1])/d;
        if(f[i-1]>g[i-1]) { p=1.0-p;q=1.0-q; }
    }
    printf("%.6lf\n",f[n]);
}
int main() {
    int t;
    scanf("%d",&t);
    while(t--) {work();}
    return 0;
}

猜你喜欢

转载自blog.csdn.net/force_chl/article/details/80547674