题意: 题目大意:有一个小偷要偷银行的钱,可是他偷没家银行总是有一定的概率被抓,现在给了你一个概率P,只要他被抓的概率乘积不大与P,他就是安全的。问你在他安全的情况下,他最多可以偷多少钱。
思路:还是和大多数人一样第一次想错了。吧概率当作背包,原本以为只需要扩大100倍概率将其变成整数就行了,然后发现有精度误差,有选择了long double发现交上去还是wa了。无奈,看了题解原来是将钱的总数看成背包,概率看成价值。
dp[i]表示可以安全逃脱的概率。
dp[j] 表示获得金额 j 时的安全概率。这里用滚动数组,得方程 dp[j] = max(dp[j], dp[i-a[i]]*(1-b[i]) 其中a表示银行金额,b表示被抓概率。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define eps 1e-8
using namespace std;
const int maxn = 10005;
double dp[maxn], p, v[maxn];
int n, t, val[maxn], sum;
int main() {
scanf("%d", &t);
while(t--) {
sum = 0;
memset(dp, 0, sizeof(dp));
cin >> p >> n;
for(int i = 1; i <= n; i++) {
cin >> val[i] >> v[i];
sum += val[i];
}
dp[0] = 1.0; //dp表示安全概率
for(int i = 1; i <= n; i++) {
for(int j = sum; j >= val[i]; j--) {
dp[j] = max(dp[j], dp[j - val[i]] * (1.0 - v[i]));
}
}
int i;
for( i = sum; i >= 0; i--) {
if(dp[i] - (1 - p) > eps) break;
}
printf("%d\n", i);
}
return 0;
}