题目简述:给出一个被抓概率,在概率之下则是安全的,给出n个银行的现金及被抓概率,求在小于被抓概率下最多能抢多少钱;
总体思路:这是一道01背包题,但稍有些变形,即要把能抢银行的总钱数当做背包容量,因为每个银行的钱数是固定的,一个银行的这些钱就是一个整体,所以这就要求背包恰好装满;
细节考虑:用dp[j]表示抢到j的钱数对应的安全概率,初始化时只有什么钱都不抢的概率是最大,所以dp[0]=1,其余都为0;接下来就是决定第i个的钱抢不抢,即判断dp[j]与dp[j-m[i]]*(1-p[i])(p[i]表示抢钱i的被抓概率)的大小关系,当然是安全概率越大越好了,所以最后的状态转移方程为dp[j]=max(dp[j],dp[j-m[i]]*(1-p[i])),j>=m[i];
代码实现如下:
#include<stdio.h>
#include<string.h>
const int Max=10010;
int m[110];
double p[110];
double dp[Max];
int main(){
int t;
scanf("%d",&t);
while(t--){
int n;
double sp;
scanf("%lf%d",&sp,&n);
int sum=0;
for(int i=1;i<=n;i++){
scanf("%d%lf",&m[i],&p[i]);
sum+=m[i];
}
memset(dp,0,sizeof(dp));
dp[0]=1.0;
for(int i=1;i<=n;i++){
for(int j=sum;j>=m[i];j--){
if(dp[j-m[i]]*(1-p[i])>dp[j])
dp[j]=dp[j-m[i]]*(1-p[i]);
}
}
/*for(int i=0;i<=sum;i++)
printf("%lf ",dp[i]);
printf("\n");*/
for(int i=sum;i>=0;i--){
if(dp[i]>(1.0-sp)){
printf("%d\n",i);
break;
}
}
}
return 0;
}