1. 程式人生 > >bzoj1419 Red is good

bzoj1419 Red is good

https sample zoj size style red ems swap HP

1419: Red is good

Time Limit: 10 Sec Memory Limit: 64 MB
Submit: 1195 Solved: 554
[Submit][Status][Discuss]

Description

桌面上有R張紅牌和B張黑牌,隨機打亂順序後放在桌面上,開始一張一張地翻牌,翻到紅牌得到1美元,黑牌則付 出1美元。可以隨時停止翻牌,在最優策略下平均能得到多少錢。

Input

一行輸入兩個數R,B,其值在0到5000之間

Output

在最優策略下平均能得到多少錢。

Sample Input

5 1

Sample Output

4.166666

HINT

輸出答案時,小數點後第六位後的全部去掉,不要四舍五入.

分析:很明顯這是一道dp題.

   我一開始想的狀態是f[i][j]表示還剩i張紅牌,j張黑牌時的期望. 那麽f[i][j] = (i + 1) / (i + j + 1) * (f[i + 1][j] + 1) + (j + 1) / (i + j + 1) * (f[i][j + 1] - 1). 如果停止翻牌了,f[i][j] = 0.

   這樣會有一個問題:如果已經停止翻牌了,f[i][j] = 0,這個狀態是能夠轉移到其它狀態去的,顯然是不合法的.

   那麽倒推,假設當前狀態是合法的. 令f[i][j]表示已經考慮了i張紅牌,j張黑牌的期望. 那麽f[i][j] = i / (i + j) * (f[i - 1][j] + 1) + j / (i + j) * (f[i][j - 1] - 1). 因為要考慮到停止翻牌這種情況. 和0取max即可.這樣每一個狀態就都是合法的了.

   註意使用滾動數組!最後答案不進位要特殊處理一下.

#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>

using namespace std;

int n,m,now,last;
double f[2][5010];

int main()
{
    now = 0,last = 1;
    scanf("%d%d",&n,&m);
    for (int i = 0; i <= n; i++)
    {
        swap(now,last);
        f[now][
0] = i; for (int j = 1; j <= m; j++) { double temp1 = (double)i / (double)(i + j); double temp2 = (double)j / (double)(i + j); f[now][j] = max(0.0,temp1 * (f[last][j] + 1) + temp2 * (f[now][j - 1] - 1)); } } f[now][m] *= 1000000; f[now][m] = floor(f[now][m]); printf("%.6lf\n",f[now][m] / 1000000); return 0; }

bzoj1419 Red is good