标签:概率,动态规划
题意:一共t组数据,每组数据给定一个数字n和一个概率pp,给出n家银行的钱数v[i]和失败率p[i],问在失败率不超过pp的情况下最多能抢多少钱(注意抢劫银行是互不独立的,也就是说抢劫后一家银行的前提是抢劫前一家银行没有失败)
题解
题目读下来发现很像01背包问题,只不过重量变成了概率,那么稍微改变一下dp的定义即可
我们定义dp[i]表示钱数为i时的最小失败率,因为抢劫后一家银行的前提是抢劫前一家银行没有失败,所以转移的时候概率的变化就是上一次累计的失败率 +(1 - 上一次累计的失败率)* 这一次的失败率
实现过程和01背包类似,最后从最大可能获得的钱数开始从大到小枚举,如果当前概率小于等于给定概率,输出当前钱数即可
代码实现
#include <algorithm>
#include <iostream>
#include <stdio.h>
#include <iomanip>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <set>
#include <map>
#define ll long long
using namespace std;
int t, n;
double pp, p[110], dp[10050];
int v[110];
int main(){
cin >> t;
for(int k = 1; k <= t; k++){
cin >> pp >> n;
int mx = 0;
for(int i = 1; i <= n; i++){
cin >> v[i] >> p[i];
mx += v[i];
}
for(int i = 1; i <= mx; i++) dp[i] = 10050;
for(int i = 1; i <= n; i++){
for(int j = mx; j >= v[i]; j--){
dp[j] = min(dp[j], dp[j - v[i]] + (1 - dp[j - v[i]]) * p[i]);
}
}
for(int i = mx; i >= 0; i--){
if(dp[i] <= pp){
cout << "Case " << k << ": " << i << "\n";
break;
}
}
}
return 0;
}