ZOJ 3329 One Person Game(概率DP)
2014-11-06 22:24
507 查看
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3329
题意:有三个骰子,分别有k1,k2,k3个面,每次掷骰子,初始分数为0,如果三个面分别为a,b,c则分数置0,否则加上三个骰子的分数之和,当分数大于n时结束。求游戏的期望步数
思路:期望一般逆推,概率一般正推,思路出自这里的题解,写得很好:http://blog.csdn.net/morgan_xww/article/details/6775853
设 E[i]表示现在分数为i,到结束游戏所要掷骰子的次数的期望值。
显然 E[>n] = 0; E[0]即为所求答案;
E[i] = ∑Pk*E[i+k] + P0*E[0] + 1; (Pk表示点数和为k的概率,P0表示分数清零的概率)
由上式发现每个 E[i]都包含 E[0],而 E[0]又是我们要求的,是个定值。
设 E[i] = a[i]*E[0] + b[i];
将其带入上面的式子:
E[i] = ( ∑Pk*a[i+k] + P0 )*E[0] + ∑Pk*b[i+k] + 1;
显然,
a[i] = ∑Pk*a[i+k] + P0;
b[i] = ∑Pk*b[i+k] + 1;
当 i > n 时:
E[i] = a[i]*E[0] + b[i] = 0;
所以 a[i>n] = b[i>n] = 0;
可依次算出 a
,b
; a[n-1],b[n-1] ... a[0],b[0];
则 E[0] = b[0]/(1 - a[0]);
#include <cstdlib>
#include <cctype>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <string>
#include <iostream>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <bitset>
#include <functional>
#include <utility>
using namespace std;
const int maxn = 100010;
const int maxm = 200020;
const int inf = 0x3f3f3f3f;
double x[600], y[600];
double p[100];
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
int n, k1, k2, k3, a, b, c;
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(x, 0, sizeof(x));
memset(y, 0, sizeof(y));
for(int i = n; i >= 0; i--)
{
for(int j = 1; j <= k1 + k2 + k3; j++)
{
x[i] += x[i + j] * p[j];
y[i] += y[i + j] * p[j];
}
x[i] += p0;
y[i] += 1;
}
printf("%.16lf\n", y[0] / (1 - x[0]));
}
return 0;
}
题意:有三个骰子,分别有k1,k2,k3个面,每次掷骰子,初始分数为0,如果三个面分别为a,b,c则分数置0,否则加上三个骰子的分数之和,当分数大于n时结束。求游戏的期望步数
思路:期望一般逆推,概率一般正推,思路出自这里的题解,写得很好:http://blog.csdn.net/morgan_xww/article/details/6775853
设 E[i]表示现在分数为i,到结束游戏所要掷骰子的次数的期望值。
显然 E[>n] = 0; E[0]即为所求答案;
E[i] = ∑Pk*E[i+k] + P0*E[0] + 1; (Pk表示点数和为k的概率,P0表示分数清零的概率)
由上式发现每个 E[i]都包含 E[0],而 E[0]又是我们要求的,是个定值。
设 E[i] = a[i]*E[0] + b[i];
将其带入上面的式子:
E[i] = ( ∑Pk*a[i+k] + P0 )*E[0] + ∑Pk*b[i+k] + 1;
显然,
a[i] = ∑Pk*a[i+k] + P0;
b[i] = ∑Pk*b[i+k] + 1;
当 i > n 时:
E[i] = a[i]*E[0] + b[i] = 0;
所以 a[i>n] = b[i>n] = 0;
可依次算出 a
,b
; a[n-1],b[n-1] ... a[0],b[0];
则 E[0] = b[0]/(1 - a[0]);
#include <cstdlib>
#include <cctype>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <string>
#include <iostream>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <bitset>
#include <functional>
#include <utility>
using namespace std;
const int maxn = 100010;
const int maxm = 200020;
const int inf = 0x3f3f3f3f;
double x[600], y[600];
double p[100];
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
int n, k1, k2, k3, a, b, c;
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(x, 0, sizeof(x));
memset(y, 0, sizeof(y));
for(int i = n; i >= 0; i--)
{
for(int j = 1; j <= k1 + k2 + k3; j++)
{
x[i] += x[i + j] * p[j];
y[i] += y[i + j] * p[j];
}
x[i] += p0;
y[i] += 1;
}
printf("%.16lf\n", y[0] / (1 - x[0]));
}
return 0;
}
相关文章推荐
- ZOJ 3329 One Person Game(概率DP)
- ZOJ 3329 One Person Game (概率DP)
- ZOJ 3329 One Person Game(概率dp)
- ZOJ 3329 One Person Game(概率dp)
- ZOJ 3329 One Person Game 带环的概率DP
- zoj 3329 One Person Game (有环 的 概率dp)
- ZOJ-3329 One Person Game (概率DP)
- ZOJ 3329 One Person Game 带环的概率DP
- ZOJ 3329 One Person Game(概率DP,求期望)★
- zoj 3329 One Person Game 概率dp
- ZOJ - 3329 One Person Game(概率dp)
- ZOJ 3329 One Person Game(概率DP、求期望)
- ZOJ 3329 One Person Game(概率dp 经典)
- ZOJ 3329-One Person Game(概率dp,迭代处理环)
- ZOJ 3329 One Person Game [概率DP]
- zoj 3329 One Person Game(概率dp,期望)
- zoj 3329 One Person Game 概率dp(有环)
- ZOJ 3329 One Person Game (概率DP)
- ZOJ 3329 One Person Game (概率dp 难)
- zoj 3329 One Person Game 概率dp