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
Solution
设
为还剩
个石子时轮到Alice,Alice的胜率,
为还剩
个石子时轮到Bob,Alice的胜率
假设每一次都是拿走石头最优,则会有
将两式化为可以递推的形式,使
从
和
转移,
同理
最终化为:
好的,但是有个问题,就是并不一定每次都是拿走石头最优,万一这次拿走石头后对方马上就赢了呢?
所以说有时候可能会选择不拿走石子
不拿走石子时则会有:
忽然发现不就把 分别对调一下么
什么时候拿走石头最优呢?若成功拿走石子的收益大于不拿走石子的收益者拿走,否则不拿走
对比
即可
代码如下:
#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;
}