http://acm.hdu.edu.cn/showproblem.php?pid=5781
题意:Alice忘记了自己银行里存了多少钱,只记得在[0,k]之间。每次取钱如果余额足够就出钱,否则警告一次,警告超过w次就会把你抓起来,在不想被警察抓起来的前提下,Alice采取最优策略,求期望取钱多少次能知道自己存了多少钱。
7
考虑期望dp[i][j]表示钱在0-i之间,最多可被警告j次
对于当前的状态dp[i][j],下一次取钱的范围可能是0-i
假设我们取了p
那么 有 p/(i+1)的概率被警告,因为钱在0- p-1,因此 下一个状态为dp[p-1][j-1] +1
反之又1- p/(i+1)的概率出钱,即钱在 p到i,因此下一个状态为dp[i-p+1][j]
所以转移方程为 dp[i][j]=min(dp[i][j],dp[i-p][j]*(i-p+1)/(i+1) +
dp[p-1][j-1]*p/(i+1) +1) ;
预处理o1查询即可
#include <bits/stdc++.h>
using namespace std;
const double g = (1 + sqrt(5.0)) / 2.0;
double dp[2005][20];
const double inf=1e16;
int main()
{
//dp[i][j]表示钱在0-i之间,最多可被警告j次
for (int i=0; i<=2000; i++)
for (int j=0; j<=15; j++)
dp[i][j]=inf;
for (int j=0; j<=15; j++)
dp[0][j]=0;
for (int i=1; i<=2000; i++)
{
for (int j=1; j<=15; j++)
{
for (int p=1; p<=i; p++)
{
dp[i][j]=min(dp[i][j],dp[i-p][j]*(i-p+1)/(i+1) +
dp[p-1][j-1]*p/(i+1) +1) ;
}
}
}
int k,w;
while(scanf("%d%d",&k,&w)!=EOF)
{
w=min(w,15);
printf("%.6lf\n",dp[k][w]);
}
return 0;
}