題意,打網絡賽,若打進前200,該賬號加1分,否則扣2分(若當前爲0分,扣完還是0分),有兩個賬號,一開始都是0分,每次選低分的打比賽,問最後任意一個賬號達到20分需要的輪數的期望。
定義dp[i] 當前分數到 20分的輪數的期望。
dp[i] = dp[i + 1]*p + dp[i - 2]*(1 - p) + 1;
但是這個方程不能用來遞推,因爲你不知道初態是怎麼樣的,因爲初態就是你要求的東西。
那麼將問題進行轉化,定義一個 t[i] = dp[i + 1] - dp[i],那麼只需要考慮從初態到下一個狀態的變化量就好了,不需要知道初態爲多少。
把dp的式子代入 t[i] ,求得 t[i + 1] = (t[i] - t[i - 2]*q)/p,這個方程就是可以遞推的了。
來考慮該式子的初態應該爲多少,因爲 0 狀態還會回到自身,所以可以直接求得 t[0] = 1/p,然後同理再一次代入t[1],t[2],是可以直接遞推出來的。
再考慮兩個賬號的問題,因爲每次選低分賬號...那麼兩個賬號肯定都要到達19分...那麼就 dp[19]*2,再加上一個 dp[20] - dp[19]不就是答案了嗎。
dp[19] = t[0] + ... + t[18]
dp[20] - dp[19] = t[19]
/*************************************************************************
> File Name: source.cpp
> Author: oldflag
> Created Time: 星期五 9/30 14:40:18 2016
************************************************************************/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <cmath>
#include <cstdlib>
#include <stack>
#include <queue>
using namespace std;
typedef long long LL;
float p, sum, t[21], q;
int main()
{
while(scanf("%f", &p) != EOF)
{
sum = 0;
q = 1 - p;
t[0] = 1/p;
t[1] = t[0]/p;
t[2] = t[1]/p;
sum = t[0] + t[1] + t[2];
for(int i = 3; i < 20; i++)
{
t[i] = (t[i - 1] - t[i - 3]*q)/p;
sum += t[i];
}
printf("%.6lf\n", sum*2 - t[19]);
}
return 0;
}