题目: LINK
题意:
有n人要激活游戏,n个人排成一个队列(Tomato最初排名为m),
对于队列中的第一个人,在激活的时候有以下4种情况:
1.激活失败:留在队列中继续等待下一次激活(概率p1)
2.失去连接:激活失败,出队列然后排到队列的尾部(概率p2)
3.激活成功:出队列(概率p3)
4.服务挂了:服务器停止服务了,所有人都无法激活了(概率p4)
求服务器挂了,此时Tomato的排名<=k的概率
这个求概率有点类似期望的求法。
dp[i][j]表示队列一共i个人, 当前tomato处于第j个,达到结果的概率
j == 1, dp[i][j] = p1 * dp[i][j] + p2 * dp[i][i] + p4;
1 < j <= k, dp[i][j] = p1 * dp[i][j] + p2 * dp[i][j-1] + p3 * dp[i-1][j-1] + p4;
k < j <= i, dp[i][j] = p1 * dp[i][j] + p2 * dp[i][j-1] + p3 * dp[i-1][j-1];
化简可以得到
令pp2 = p2 / ( 1 - p1) , pp3 = p3 / (1 - p1) , pp4 = p4 / (1 - p1)
j == 1, dp[i][j] = pp2 * dp[i][i] + pp4 ;
1 < j <= k, dp[i][j] = pp2 * dp[i][j-1] + pp3 * dp[i-1][j-1] + pp4;
k < j <= i, dp[i][j] = pp2 * dp[i][j-1] + pp3 * dp[i-1][j-1];
dp[i][j] 是i 一层一层的求的在求dp[i][]时dp[i-1][]已经求出来了。
所以可以写成
dp[i][1] = pp2 * dp[i][i] + C[1];
dp[i][2] = pp2 * dp[i][1] + C[2];
dp[i][3] = pp2 * dp[i][2] + C[3];
.......
dp[i][i] = pp2 * dp[i][i-1] + C[i];
这个式子可以不断代入求的dp[i][]的解,最后输出dp[n][m]即可。
注意一个WAWAWAWAWA的地方 特判断p1 + p2 接近1的时候直接输出0.00000,因为这种情况下题目要求的情况出现概率几乎为0,但是算的话会出现错误。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <cmath>
#include <queue>
#include <map>
#include <set>
using namespace std;
#define INF 1000000000
//typedef __int64 LL;
#define N 2010
int n, m, k;
double p1, p2, p3, p4;
double pp1, pp2, pp3, pp4;
double dp[N][N], C[N];
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif // ONLINE_JUDGE
while(scanf("%d%d%d%lf%lf%lf%lf", &n, &m, &k, &p1, &p2, &p3, &p4) != EOF) {
if(1.0 - p1 - p2 < 1e-9) {
puts("0.00000"); continue; // this ? !
}
pp2 = p2 / (1.0 - p1);
pp3 = p3 / (1.0 - p1);
pp4 = p4 / (1.0 - p1);
memset(dp, 0, sizeof(dp));
dp[1][1] = pp4 / (1.0 - pp2);
double a, b;
for(int i = 2; i <= n; i++) {
a = pp2; b = pp4;
C[1] = pp4;
for(int j = 2; j <= i; j++) {
double aa, bb;
if(j <= k) {
C[j] = pp3 * dp[i-1][j-1] + pp4;
}
else {
C[j] = pp3 * dp[i-1][j-1];
}
aa = a * pp2; bb = b * pp2 + C[j];
a = aa; b = bb;
}
dp[i][i] = b / (1.0 - a);
double temp = dp[i][i];
for(int j = 1; j < i; j++) {
dp[i][j] = pp2 * temp + C[j];
temp = dp[i][j];
}
}
printf("%.5lf\n", dp[n][m]);
}
return 0;
}