hdu 5781 ATM Mechine(概率dp)
题意:Alice忘记在银行里存了多少钱,只记得在[0,k]之间。每次取钱如果余额大于取钱数就出钱,否则警告一次,警告超过w次就会被警察带走,Alice采用最优策略,在不被带走的情况下,求期望--取多少次钱就可以知道自己的余额!
ATM Mechine
E(i,j):存款的范围是[0,i],还可以被警告j次的期望值。
E(i,j) = maxk=1ii+1i−k+1∗E(i−k,j)+i+1k∗E(k−1,j−1)+1 这样时间复杂度是O(K2W)的。 假如Alice使用的是二分策略,那么在最坏情况下至多被警告⌈log2K⌉ 次。 于是W:=min(W,15)就可以了。
然后clar有人问y是不是要整数。由于存款是整数,你取小数的钱没有任何意义啊。
题解出处:http://bestcoder.hdu.edu.cn/blog/
/*by*/ #include <iostream> #include <algorithm> #include <cstdio> #include <cstring> using namespace std; typedef long long LL; const LL N=2010; const LL mod=1000000007; const LL INF=0x3f3f3f; double dp[N][13];/*dp[i][j]:当存款范围为[0,i],还可以被警告的次数为j的期望*/ /* dp公式:dp[i][j]=min(dp[i][j],dp[i-k][j]*(i-k+1.0)/(i+1.0)+dp[k-1][j-1]*k/(i+1.0)+1); [0,1]表示有i+1种情况, 取钱两种状态:一,当取k且不被警告;二.余额不足k,则此时的存款范围是[0,k-1]; */ void init() { for(int i=1; i<N; i++) for(int j=0; j<=12; j++) dp[i][j]=INF; for(int i = 1; i < N; i++) for(int j=1; j<=12; j++) for(int k=1; k<=i; k++) dp[i][j]=min(dp[i][j],dp[i-k][j]*(i-k+1.0)/(i+1.0)+dp[k-1][j-1]*k/(i+1.0)+1); } int main() { int n,m; init(); while(~scanf("%d%d",&n,&m)) { if(n == 1) { printf("1.000000\n"); continue; } printf("%.6lf\n",dp[n][min(m,12)]); } return 0; }