题意:有个强盗要偷银行,先给出强盗被捕的总概率,也就是最后被捕的概率需要低于这个数,然后给出银行的个数,接着给出每个银行被偷这个强盗的比例,和这个银行的钱数,最后问这个强盗最多能偷多少钱?
题解:这是一道很好的题,首先都在想的是让强盗被捕的总概率为背包容量,然后让每个银行的金钱作为物品的价值,最后就这样求解01背包?这样对么,对的话递推方程又该如何写?第一,这个背包容量是浮点数,第二,这个概率如何算?偷了两个银行的概率怎么算呢?简单的加起来,简单的乘起来?这就得用到概率论的事件独立的思想,偷第一个银行和偷第二个银行的的被捕的概率是相互独立的,那么最后被捕的概率就是,也就是P(A)+P(B)-P(AB),这样不好递推,另外还需知道的是A和B独立的话,必然和是相互独立的,那么就可以这样算,我们用钱数做背包容量,然后价值为不被抓的概率,考虑边界情况,不偷任何钱的概率是1,肯定啊,不偷任何钱不被抓的概率就是1,不偷钱你抓我干嘛!然后递推方程为:
,就是偷j点钱不被抓的最大概率,最后通过比较导出最后的答案,挺有意思的一道题,推荐推荐。
最后注意边界条件为什么除了dp[0]是1,剩下初始的都是0了,当然了,偷的钱要把背包始终装满啊。
附上代码:
#include<bits/stdc++.h>
using namespace std;
const int maxv=1e4+5;
const int maxn=1e2+5;
int t,n,m[maxn];
double p,pp[maxn];
double dp[maxv];
int main()
{
scanf("%d",&t);
while(t--){
scanf("%lf%d",&p,&n);
int sum=0;
for(int i=1;i<=n;i++){
scanf("%d%lf",&m[i],&pp[i]);
sum+=m[i];
}
memset(dp,0,sizeof(dp));
dp[0]=1;
for(int i=1;i<=n;i++){
for(int j=sum;j>=m[i];j--){
dp[j]=max(dp[j],dp[j-m[i]]*(1-pp[i]));
}
}
for(int j=sum;j>=0;j--){
if(dp[j]>(1-p)){
printf("%d\n",j);
break;
}
}
}
return 0;
}