hdu5781 期望dp
hdu5781 ATM Mechine
传送门
题意
\(Alice\)从取款机里取存款,不知道存款金额,但是知道存款的上限是\(K(1\leq K\leq 2000)\),每次想要取出一定数量的存款,如果想取的存款数不超过剩余的存款数,则可以取出,否则会被警告,警告次数超过\(W(1\leq W\leq 2000)\)会被警察带走,\(Alice\)采取最优策略,计算在不被警察带走的情况下将钱取完的取钱次数期望
题解
期望dp
\(dp[i][j]\)表示剩余存款数上限为\(i\),剩余警告次数为\(j\)时,将钱取完的期望次数
状态转移:\(dp[i][j]=min_{k=1}^{i}\{\frac{i+1-k}{i+1}*dp[i-k][j]+\frac{k}{i+1}*dp[k-1][j-1]+1\}\)
由于剩余存款的上限是\(i\),也就是可能的值为\([0,i]\),所以一共有\((i+1)\)个
状态转移方程中的前一项表示剩余存款数大于等于\(k\)时,也就是取走\(k\)不会被警告时的转移过程,此时由于取走\(k\)没有被警告,所以可以知道剩余存款数的上限是\((i-k)\),可以由\(dp[i-k][j]\)转移过来。后一项表示存款数小于\(k\)时的转移过程,此时由于取走\(k\)被警告,所以可以知道剩余存款数的上限是\((k-1)\),可以由\(dp[k-1][j-1]\)转移过来
由于\(Alice\)选择最优策略,可以通过二分选择取走的存款数,也就是最多被警告\(\log K\)次,所以\(W=min(W,\log K)\),可以将时间复杂度从\(O(K^2W)\)降为\(O(K^2\log K)\)。由于\(\log K<11\),也可以直接设置\(W=min(W,11)\)
预处理\(dp\)数组,多组数据,\(O(1)\)查询
#include<iostream>
#include<cstdio>
#include<vector>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<cstring>
#include<string>
#include<sstream>
#include<cmath>
#include<ctime>
#include<climits>
#include<algorithm>
#define LL long long
#define PII pair<int,int>
#define PLL pair<LL,LL>
#define PLI pair<LL,int>
#define pi acos(-1.0)
#define eps 1e-6
#define lowbit(x) x&(-x)
using namespace std;
const int maxk=2010;
const double inf=0x3f3f3f3f;
int k,w;
double dp[maxk][15];
void init(){
for(int i=0;i<=2000;i++){
for(int j=0;j<=11;j++){
dp[i][j]=inf;
if(!i) dp[i][j]=0;
else if(j){
for(int k=1;k<=i;k++){
dp[i][j]=min(dp[i][j],1.0*(i+1-k)/(i+1)*dp[i-k][j]+1.0*k/(i+1)*dp[k-1][j-1]+1);
}
}
}
}
}
int main(){
init();
while(~scanf("%d%d",&k,&w)){
w=min(w,11);
printf("%.6f\n",dp[k][w]);
}
return 0;
}