Input
The first line of input gives T, the number of cases. For each scenario, the first line of input gives a floating point number P, the probability Roy needs to be below, and an integer N, the number of banks he has plans for. Then follow N lines, where line j gives an integer Mj and a floating point number Pj .
Bank j contains Mj millions, and the probability of getting caught from robbing it is Pj .
Output
For each test case, output a line with the maximum number of millions he can expect to get while the probability of getting caught is less than the limit set.
Notes and Constraints
0 < T <= 100
0.0 <= P <= 1.0
0 < N <= 100
0 < Mj <= 100
0.0 <= Pj <= 1.0
A bank goes bankrupt if it is robbed, and you may assume that all probabilities are independent as the police have very low funds.
Sample Input
3
0.04 3
1 0.02
2 0.03
3 0.05
0.06 3
2 0.03
2 0.03
3 0.05
0.10 3
1 0.03
2 0.02
3 0.05
Sample Output
2
4
6
题意:
给出几组数据,每组数据第一行是总被抓概率P(最后求得的总概率必须小于他,否则被抓),然后是想抢的银行数n。然后n行,每行分别是该银行能抢的钱数m[i]和被抓的概率p[i],求在不被抓的情况下最多能抢多少钱?
思路:
直接套01背包的框架的话,将概率看成背包的容量,进行dp,这样马上就会有一个问题了,概率是浮点数,根本能用枚举的方法去递推。所以要换个思路。我们把所有n个银行所有的钱看做是背包的容量,不被抓的概率看成价值,那么 dp[j] 的意义就变成了,抢到 j million的钱的时候且不被抓的概率。并且应该让不被抓的概率越大越好。状态转移方程为:
dp[j]=max(dp[j],dp[j−m[i]])∗(1−p[i])
d
p
[
j
]
=
m
a
x
(
d
p
[
j
]
,
d
p
[
j
−
m
[
i
]
]
)
∗
(
1
−
p
[
i
]
)
最后从后往前遍历dp数组,找到第一个大于 (1 - P)的 j ,j 就是答案。
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxn = 1e5+5;
int main()
{
int t;
cin >> t;
double p[maxn];
int m[maxn];
double dp[maxn+5];
while(t--) {
double P;
int n;
cin >> P >> n;
int sum = 0;
memset(m,0,sizeof(m));
memset(p,0,sizeof(p));
for (int i = 0; i < n; ++i) {
cin >> m[i] >> p[i];
sum += m[i];
}
memset(dp,0,sizeof(dp));
dp[0] = 1;
for (int i = 0; i < n; ++i) {
for (int j = sum; j >= 0; --j) {
if (j >= m[i])
dp[j] = max(dp[j],dp[j-m[i]]*(1-p[i]));
}
}
for (int i = sum; i >= 0; --i) {
if (dp[i] > (1.0-P) ) {
cout << i << endl;
break;
}
}
}
return 0;
}