题意:
有不超过k元钱,若取钱大于剩余,atm会报错,问在不超过w次报错下,取出所有钱的最小期望。
题解:
设当前状态dp[i][j],i为最大钱数,j为剩余报错数,
若i > 0、 j > 0,
则dp[i][j] = minik=1(i−k+1i+1∗dp[i−k][j]+ki+1∗dp[k−1][j−1]+1),
前一项为k不超过剩余的情况,后一项为超过,1为当前操作的一步。
i = 0时为0, j=0时为无穷大。
复杂度O(k2w) 因为k<2000, 若采取二分,最坏步数为log20002, 所以w = min(w, 11), 不会超时。
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 2005;
const double INF = 1e12;
double f[N][16];
double cal(int k, int w)
{
if (k == 0) return 0;
if (w == 0) return INF;
if (f[k][w] > 0) return f[k][w];
double ans = INF;
for (int i = 1; i <= k; ++i) {
ans = min(ans, cal(i-1,w-1)*i/(k+1) + cal(k-i,w)*(k+1-i)/(k+1) + 1);
}
return f[k][w] = ans;
}
int main(int argc, char const *argv[])
{
int k, w;
while (~scanf("%d%d", &k, &w)) {
w = min(w, 15);
printf("%.6f\n", cal(k, w));
}
return 0;
}