Robberies HDU - 2955(01背包+概率论+边界处理+好题)

传送门

题意:有个强盗要偷银行,先给出强盗被捕的总概率,也就是最后被捕的概率需要低于这个数,然后给出银行的个数,接着给出每个银行被偷这个强盗的比例,和这个银行的钱数,最后问这个强盗最多能偷多少钱?

题解:这是一道很好的题,首先都在想的是让强盗被捕的总概率为背包容量,然后让每个银行的金钱作为物品的价值,最后就这样求解01背包?这样对么,对的话递推方程又该如何写?第一,这个背包容量是浮点数,第二,这个概率如何算?偷了两个银行的概率怎么算呢?简单的加起来,简单的乘起来?这就得用到概率论的事件独立的思想,偷第一个银行和偷第二个银行的的被捕的概率是相互独立的,那么最后被捕的概率就是P(A\bigcup B ),也就是P(A)+P(B)-P(AB),这样不好递推,另外还需知道的是A和B独立的话,必然\bar{A}\bar{B}是相互独立的,那么就可以这样算,我们用钱数做背包容量,然后价值为不被抓的概率,考虑边界情况,不偷任何钱的概率是1,肯定啊,不偷任何钱不被抓的概率就是1,不偷钱你抓我干嘛!然后递推方程为:

dp[j]=max(dp[j],dp[j-m[i]]*(1-p[i])),就是偷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;
}

猜你喜欢

转载自blog.csdn.net/zhouzi2018/article/details/86519471
今日推荐