【BZOJ 2318】 2318: Spoj4060 game with probability Problem(概率DP)

2318: Spoj4060 game with probability Problem

Time Limit: 1 Sec  Memory Limit: 128 MB
Submit: 371  Solved: 173

Description

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

现在Alice先手投掷硬币,假设他们都想赢得游戏,问你Alice胜利的概率为多少。

Input

第一行一个正整数t,表示数据组数。

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

Output

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

Sample Input

1

1 0.5 0.5

Sample Output

0.666667

HINT

数据范围:

1<=t<=50

0.5<=p,q<=0.99999999

对于100%的数据 1<=n<=99999999

Source

【分析】

  这种题的特点是转移成环,一般来说要消元。不过这题转台转移量少,可以手动消元。

  打了两种打法:

  1、【我自己的方法】

  f[i][0]表示0作为先手,面对i个棋子,0获胜概率。

  f[i][1]表示1作为先手,面对i个棋子,1获胜概率。

  f[i][0]=1-p*min(f[i][1],f[i-1][1])-(1-p)*max(f[i][1],f[i-1][1])

  f[i][1]=1-q*min(f[i][0],f[i-1][0])-(1-q)*max(f[i][0],f[i-1][0])

  但是这里有min和max,不能直接移项。共有四种情况,每种情况都算一下,然后判断这个min和max是否成立。

  【其实会不会有多解sm的呢?我也不清楚,但是答案肯定是符合的。。至于为什么只有答案符合,我也不会证明。但是这样是可以过的。

  【其实主要是这样判断,最值里面有不确定因素,其实判断f[i-1][0]和1-f[i-1][1]也是可以的,就不用枚举4种情况那么麻烦了

  

  代码:

  

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 using namespace std;
 7 #define Maxn 1100
 8
 9 double f[Maxn][2];
10
11 int main()
12 {
13     int T;
14     scanf("%d",&T);
15     while(T--)
16     {
17         int n;
18         double p,q;
19         scanf("%d%lf%lf",&n,&p,&q);
20         n=min(n,1000);
21         f[0][1]=f[0][0]=0;
22         for(int i=1;i<=n;i++)
23         {
24             double A0=f[i-1][0],A1=f[i-1][1],P,Q;
25             //x0=1-P*x1-(1-P)*A1
26             //x1=1-Q*x0-(1-Q)*A0
27             P=p,Q=q;
28             f[i][0]=(1-P+P*(1-Q)*A0-(1-P)*A1)/(1-P*Q);
29             f[i][1]=(1-Q+Q*(1-P)*A1-(1-Q)*A0)/(1-P*Q);
30             if(f[i][1]<=A1&&f[i][0]<=A0) continue;
31             P=p,Q=1-q;
32             f[i][0]=(1-P+P*(1-Q)*A0-(1-P)*A1)/(1-P*Q);
33             f[i][1]=(1-Q+Q*(1-P)*A1-(1-Q)*A0)/(1-P*Q);
34             if(f[i][1]<=A1&&f[i][0]>=A0) continue;
35             P=1-p,Q=q;
36             f[i][0]=(1-P+P*(1-Q)*A0-(1-P)*A1)/(1-P*Q);
37             f[i][1]=(1-Q+Q*(1-P)*A1-(1-Q)*A0)/(1-P*Q);
38             if(f[i][1]>=A1&&f[i][0]<=A0) continue;
39             P=1-p,Q=1-q;
40             f[i][0]=(1-P+P*(1-Q)*A0-(1-P)*A1)/(1-P*Q);
41             f[i][1]=(1-Q+Q*(1-P)*A1-(1-Q)*A0)/(1-P*Q);
42         }
43         printf("%.6lf\n",f[n][0]);
44     }
45     return 0;
46 }

  2、第二种方法是看别人的,代码量比我少一点。

  但是我一般不会这样表示的说。

  f[i][0]表示0面对i,0获胜概率。f[i][1]表示1面对i,0获胜概率。

  那么当f[i-1][0]>f[i-1][1],当面对i时,0肯定想拿石子,1肯定不想。

  反之不说了。

  f[i][0]=p*f[i-1][0]+(1-p)*f[i][1]

  f[i][1]=q*f[i-1][1]+(1-q)*f[i][0]

  反之

  f[i][0]=(1-p)*f[i-1][0]+p*f[i][1] 
  f[i][1]=(1-q)*f[i-1][1]+q*f[i][0]

  移项消元即可。

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 using namespace std;
 7 #define Maxn 1100
 8
 9 double f[Maxn][2];
10
11 int main()
12 {
13     int T;
14     scanf("%d",&T);
15     while(T--)
16     {
17         int n;
18         double p,q;
19         scanf("%d%lf%lf",&n,&p,&q);
20         n=min(n,1000);
21         f[0][0]=0;f[0][1]=1;
22         for(int i=1;i<=n;i++)
23         {
24             double A0=f[i-1][0],A1=f[i-1][1],P,Q;
25             if(A0<=A1) P=1-p,Q=1-q;
26             else P=p,Q=q;
27             f[i][0]=(A1*(1-P)+A0*(1-Q)*P)/(1-P*Q);
28             f[i][1]=(A0*(1-Q)+A1*(1-P)*Q)/(1-P*Q);
29         }
30         printf("%.6lf\n",f[n][0]);
31     }
32     return 0;
33 }

2017-04-22 10:17:55

时间: 2024-10-02 04:49:12

【BZOJ 2318】 2318: Spoj4060 game with probability Problem(概率DP)的相关文章

BZOJ 2318: Spoj4060 game with probability Problem( 概率dp )

概率dp... http://blog.csdn.net/Vmurder/article/details/46467899 ( from : [辗转山河弋流歌 by 空灰冰魂] ) 这个讲得很好 , 推推公式就可以 O( n ) , 但是 n 最大是99999999 , 怎么破....其实 n 很大时概率基本不动了...所以只需计算到某一个较大值时就可以停下来了... ----------------------------------------------------------------

【BZOJ2318】Spoj4060 game with probability Problem 概率

[BZOJ2318]Spoj4060 game with probability Problem Description Alice和Bob在玩一个游戏.有n个石子在这里,Alice和Bob轮流投掷硬币,如果正面朝上,则从n个石子中取出一个石子,否则不做任何事.取到最后一颗石子的人胜利.Alice在投掷硬币时有p的概率投掷出他想投的一面,同样,Bob有q的概率投掷出他相投的一面. 现在Alice先手投掷硬币,假设他们都想赢得游戏,问你Alice胜利的概率为多少. Input 第一行一个正整数t,

【BZOJ2318】【spoj4060】game with probability Problem 概率DP

链接: #include <stdio.h> int main() { puts("转载请注明出处[辗转山河弋流歌 by 空灰冰魂]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/46467899"); } 题解: fi 表示剩 i 个石头. A 先手的获胜概率. gi 表示剩 i 个石头. A 后手的获胜概率. 如果想选,对于 fi: 有 p 的概率进入 gi?1 :有 1?p 的概率进入 gi

bzoj2318 Spoj4060 game with probability Problem

2318: Spoj4060 game with probability Problem Time Limit: 1 Sec  Memory Limit: 128 MB Submit: 259  Solved: 108 [Submit][Status][Discuss] Description Alice和Bob在玩一个游戏.有n个石子在这里,Alice和Bob轮流投掷硬币,如果正面朝上,则从n个石子中取出一个石子,否则不做任何事.取到最后一颗石子的人胜利.Alice在投掷硬币时有p的概率投掷出

【bzoj2318】Spoj4060 game with probability Problem

题目描述 Alice和Bob在玩一个游戏.有n个石子在这里,Alice和Bob轮流投掷硬币,如果正面朝上,则从n个石子中取出一个石子,否则不做任何事.取到最后一颗石子的人胜利.Alice在投掷硬币时有p的概率投掷出他想投的一面,同样,Bob有q的概率投掷出他相投的一面. 现在Alice先手投掷硬币,假设他们都想赢得游戏,问你Alice胜利的概率为多少. 输入 第一行一个正整数t,表示数据组数. 对于每组数据,一行三个数n,p,q. 输出 对于每组数据输出一行一个实数,表示Alice胜利的概率,保

[CF442B] Andrey and Problem (概率dp)

题目链接:http://codeforces.com/problemset/problem/442/B 题目大意:有n个人,第i个人出一道题的概率是pi,现在选出一个子集,使得这些人恰好出一个题的概率最大.问最大概率. 可以仿照背包问题来做,即每个人可问可不问. f[i][j]代表从前i个人里问j个人所获得1个题的最大概率. f[i][j] = max{ f[i-1][j], f[i-1][j-1]*(1-p[i])+z[i-1][j-1]*p[i] }; z[i][j]为从前i个人里问j个人所

rockethon2015 G2题 Inversions problem 概率dp

题意:给定n,k.k次操作,每次等概率将一个区间翻转,问最后逆序数对的期望. 思路:设dp[i][j]表示a[i]在a[j]前面的概率.每次枚举翻转的区间,更新dp[i][j],复杂度为O(n^4×k).详见代码: /********************************************************* file name: G.cpp author : kereo create time: 2015年02月09日 星期一 11时32分13秒 ************

【BZOJ 2553】[BeiJing2011]禁忌 AC自动机+期望概率dp

我一开始想的是倒着来,发现太屎,后来想到了一种神奇的方法——我们带着一个既有期望又有概率的矩阵,偶数(2*id)代表期望,奇数(2*id+1)代表概率,初始答案矩阵一列,1的位置为1(起点为0),工具矩阵上如果是直接转移那么就是由i到j概率期望都乘上1/alphabet,特别的,对于一个包含禁忌串的节点直接由其父节点指向0,而且在计算期望是多加上他的概率,最后统计答案时把答案矩阵上所有的期望加和即可,这个方法很完美的被卡精了....... #include <cstdio> #include

Codeforces 513G1 513G2 Inversions problem 概率dp

题目链接:点击打开链接 题意: 给定n ,k 下面n个数表示有一个n的排列, 每次操作等概率翻转一个区间,操作k次. 问: k次操作后逆序数对个数的期望. 思路: dp[i][j]表示 a[i] 在a[j] j前面的概率 初始就是 dp[i][j]  = 1( i < j ) 则对于翻转区间 [i, j], 出现的概率 P = 1 / ( n * (n+1) /2) 并且会导致 [i, j]内元素位置交换,枚举这次翻转的区间时所有的转移情况 #include <stdio.h> #inc