HDU 2955 Robberies (01背包,思路要转换一下,推荐!)

题意: 小A要去抢劫银行,但是抢银行是有风险的,因此给出一个float值P,当被抓的概率<=p,他妈妈才让他去冒险。
  给出一个n,接下来n行,分别给出一个Mj和Pj,表示第j个银行所拥有的钱,以及抢劫该银行被抓的可能性。
  注意:抢劫各个银行被抓的可能是独立事件!

思路: 由于被抓的可能性float型,而且不仅仅只有两位,float型精度一般小数点后6-7位,
  假若将被捕可能性看做容量,开10^6的数组,WA;开10^7的数组,MLE。
  因此若从一般的角度,即将被捕可能性转化成整数,看做容量,将抢劫的钱看作价值,是行不通的。
  而且这样求被捕的概率也比较复杂。

  这题的解法确实神!
  将银行的钱数看做容量,对应的价值是每个银行不被捕的概率,这样我们就将题目转化成求最大的不被捕的概率值(但并不是求这个)。
  用dp[j]表示偷到的钱为 j 时不被抓的概率,则状态转移方程为:
  dp[j] = max(dp[j] , dp[j-money[i]] * pro[i]);
  money[i]为第i个银行的钱,pro[i]=1-pi,即不被抓的概率。
  由于是独立事件,所以要用累乘。
  初始条件:dp[0]=1,dp[i]=0。
  最终通过从总钱数递减找到第一个大于等于期望的不被捕概率(1-p)的背包,即为不被逮捕的所能抢到的最大钱数。

 

#include <iostream>
#include <stdio.h>
#include <cstring>
#include <algorithm>

using namespace std;
const int maxn=101;
const int maxv=10005;
float dp[maxv];  //求最大的不被抓概率
float p; //被抓的概率要<=p
int n;
int sum;  //银行的总钱数
int money[maxn];
float prob[maxn];

int main()
{
    int t,val;
    float pj;
    scanf("%d",&t);
    while(t--){
        scanf("%f%d",&p,&n);
        sum=0;
        for(int i=1;i<=n;i++){
            scanf("%d%f",&val,&pj);
            sum+=val;
            money[i]=val;  //将银行里的钱当成容量
            prob[i]=1-pj;   //将不被抓的可能性当成价值
        }
        memset(dp,0,sizeof(dp));
        dp[0]=1;
        for(int i=1;i<=n;i++){
            for(int j=sum;j>=money[i];j--){
                dp[j]=max(dp[j],dp[j-money[i]]*prob[i]);
            }
        }
        int ans=0; //别忘了初始为0
        for(int i=sum;i>=1;i--){
            if(dp[i]>=1-p){
                ans=i;
                break;
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

 

posted @ 2013-12-05 14:13  辰曦~文若  阅读(415)  评论(0编辑  收藏  举报