hdu2955(好)背包转化

题目大意:有一个强盗要去几个银行偷盗,他既想多偷点钱,又想尽量不被抓到。已知各个银行的金钱数和被抓的概率,以及强盗能容忍的最大被抓概率。求他最多能偷到多少钱?

思路:背包问题,原先想的是把概率当做背包,在这个范围内最多能抢多少钱。

但是问题出在概率这里,一是因为概率是浮点数,用作背包必须扩大10^n倍来用,而浮点数精度不高输入0.04存储有可能变成0.39。二是最大被抓概率不是简单的累加。1-p = (1-p1)(1-p2)(1-p3), 其中p给定被抓概率,p1,p2,p3为各个银行被抓概率,不能是p=p1*p2*p3,(要注意给定的那个p到底是怎么算出来的)如果以被抓概率为背包容量,一开始我以为要做除法而不是减法,精度就更低了,后来才发现即使精度够了做除法也行不通,因为p不是通过p=p1*p2*p3算出来的。第二次想到把银行的钱当做背包,把(能逃跑而不是被抓)概率当做价值,这样每次计算要做乘法,总容量为所有银行的总钱数,求不超过被抓概率(即背包的概率要大于1-p)的情况下,最大的背包容量是多少。

注意:初始化边界只有dp[0]=1,这样求的是装满的情况。其他情况初始为0,这样一乘上概率还是0。

#include<bits/stdc++.h>
using namespace std;
struct bank
{
    int mon;
    float p;
}b[102];
float dp[10002];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        float x;
        int n;
        scanf("%f%d",&x,&n);
        int i,j;
        int sum=0;
        for(i=0;i<n;i++)
        {
            scanf("%d%f",&b[i].mon,&b[i].p);
            sum+=b[i].mon;
        }
        memset(dp,0,sizeof(dp));
        dp[0]=1;
        for(i=0;i<n;i++)
            for(j=sum;j>=b[i].mon;j--)
                dp[j]=max(dp[j],dp[j-b[i].mon]*(1-b[i].p));
        for(i=sum;i>=0;i--)
        {
            if(dp[i]>1-x)
            {
                printf("%d\n",i);
                break;
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_42165786/article/details/81515869
今日推荐