HDU 2955 Robberies【01背包】

来源:互联网 发布:批量上传淘宝宝贝软件 编辑:程序博客网 时间:2024/06/04 18:44

source:

点击打开链接


题意说强盗要去几个银行偷盗,已知各个银行的钱数和被抓的概率,以及强盗能容忍的最大的被抓概率。求他在被抓概率小于容忍值的情况下最多能偷到多少钱?


思路:第一反应:01背包,将每个银行当物品,钱数作为价值,被抓概率做容量。但这有问题,被概率不能当做容量,因为被抓概率并非简单的相加,而是要转化为不被抓概率相乘再用1减,于是这就不好写出递推关系了!于是换种思路,这种问题还是得01背包,只是将价值和容量换一换,将抢到的总钱数作为容量,不被抓的概率作为价值,这样就有:dp[i][j]=前i个银行中,抢到的总价值不大于j的最大不被抓的概率


写出原递推公式比较好理解:dp[i][j]=max(dp[i-1][j],dp[i-1][j-m[i]]×(1-p[i]));

进行空间优化后:从sum(所有m[i]之和)到m[i]倒着循环:dp[j]=max(dp[j],dp[j-m[i]]×(1-p[i]))

以上就算出了不大于某给定抢钱总数的情况下不被抓的概率,最后只需从sum依次往小处找,第一个是的不被抓概率大于等于1-P值时即为最大钱数!


代码如下:

#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;int m[105];double p[105],dp[10010];int main(){    int T,n,sum;    double P;    scanf("%d",&T);    for(int t=0;t<T;t++)    {        scanf("%lf%d",&P,&n);//printf("%lf\n",P);        sum=0;        for(int i=0;i<n;i++)        {            scanf("%d %lf",&m[i],&p[i]);            sum+=m[i];        }        memset(dp,0.0,sizeof(dp));        dp[0]=1;        for(int i=0;i<n;i++)            for(int j=sum;j>=m[i];j--)            dp[j]=max(dp[j],dp[j-m[i]]*(1-p[i]));  //dp[j]:目前总价值不大于j的最大不被抓的概率        for(int i=sum;i>=0;i--)            if(dp[i]>=(1-P))            {                printf("%d\n",i);                break;            }    }    return 0;}