2955 ACM 杭电 抢银行 01背包 乘法

这里写图片描述这里写图片描述


题意:
强盗抢银行,在不被抓住的情况下,想尽量多的偷点钱。已知各个银行的金钱和被抓的概率,以及强盗能容忍的最大不被抓的概率(小于等于该概率才能不被抓),求最多能抢到钱?

并不是简单的01背包问题?
1.概率是浮点数
2.最大不被抓的概率不是简单相加,由概率论可知,要抢的几家银行同时不被抓,要相乘。P=(1-P1)(1-P2)(1-P3) (P为最大不被抓的概率,P1 P2 P3为各个银行被抓的概率)

难点:
通常的01背包模板:
for(int j=v;j>=a[i].w;j–)//v是容积(拥有的总资金.)
{
dp[j]=max(dp[j],dp[j-a[i].w]+a[i].val);
}
如何和01背包联系起来。可以这么思考:钱作为v 然后dp数组里存逃跑的概率。

for(int j=total_val;j>=val[i];j--)//total_val是总钱数
{
    dp[j]=max(dp[j],dp[j-val[i]]*(1-prob[i]));
}

状态转移方程:

dp[j]=max(dp[j],dp[j-val[i])(1-prob[i])); …….dp[i]表示当抢到i元钱 时,不被抓的最小概率值。*

最后输出前遍历dp,从钱数大到小遍历,一旦满足概率:dp[i] > (1 - P),输出值,跳出循环。

#include<stdio.h>
#include<string.h>

#define max(a,b) (a>b)?a:b
#define NN 50005

int main()
{
    int T,N,val[NN];
    double P,dp[NN],prob[NN];
    scanf("%d",&T);
    while(T--)
    {
        scanf("%lf%d",&P,&N);
        int total_val=0;
        for(int i=0;i<N;i++)
        {
            scanf("%d%lf",&val[i],&prob[i]);
            total_val+=val[i];
        }
        memset(dp,0,sizeof(dp));
        dp[0]=1;
        for(int i=0;i<N;i++)
            for(int j=total_val;j>=val[i];j--)
            {
                    dp[j]=max(dp[j],dp[j-val[i]]*(1-prob[i]));
            }

            for(int i = total_val; i >= 0; i --)
            {
                 if(dp[i] > (1 - P))
                 {
                    printf("%d
", i);
                    break;
                 }
            }
    }
}

](https://img-blog.csdn.net/2018080611055363?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjEwMDQ3Mg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)

原文地址:https://www.cnblogs.com/CheeseIce/p/9588698.html