HDU 4870 Rating

題意,打網絡賽,若打進前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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章