/**
解题思路:这道题是01背包的变型。通常的题目是dp[i]代表背包装重量为i的物品的价值。而这个题目是将价值作为背包容量,将不被捉到的概率作为背包的值。状态转移方程为dp[j]=max(dp[j],dp[j-cost]*weight)。
*/
题目大意:有人想抢劫银行,给定T,代表T组测试样例,给定一个概率P即抢劫被捉概率要控制在该概率内,给一个n即有几个抢劫目标,下边n行分别是Mi,Pi,代表n个银行的存款总值和抢劫该银行的被捉率。问在小于等于P概率的前提下,能抢到的最大金额。
/**
01背包
Zero_One_Pack(cost,weight){
for(i=V;i>=cost;i--){
dp[i]=max(dp[i],dp[i-cost]+weight);
}
}
初始化时,如果要求恰好装满背包,dp[0]=0,dp[1-V]=-lim。
则合法状态为将价值为0,耗费为0的物品把容量为0的背
包装满,其他都为非法状态。
*/
#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
const int MAXN=110;
double lim_dan,dp[MAXN*MAXN];
int each_mon[MAXN],V;
double each_safe[MAXN];
double max(double a, double b){
return a>b?a:b;
}
void Zero_One_Pack(int cost,double weight){
for(int j=V;j>=cost;j--){
//由于是独立事件,概率需要相乘
dp[j]=max(dp[j],dp[j-cost]*weight);
}
}
int main(){
int t,n;
cin>>t;
double lim_dan;
while(t--){
V=0;
memset(dp,0,sizeof(dp)); //不必完全装满,初始化为0
dp[0]=1; //初始化当抢劫0价值时的安全率为1
cin>>lim_dan>>n;
for(int i=0;i<n;i++){
double rate_dan;
cin>>each_mon[i]>>rate_dan;
each_safe[i]=1-rate_dan; //计算抢劫每个银行的安全率
V+=each_mon[i]; //背包总容量
}
for(int i=0;i<n;i++){ //枚举所有银行
Zero_One_Pack(each_mon[i],each_safe[i]);
}
int i;
for( i=V;i>=0;i--){
//抢劫价值为i的钱不被捉到的概率大于等于预定概率,该价值为临界值
if(dp[i]>=1-lim_dan){
break;
}
}
printf("%d\n",i);
}
return 0;
}