hdu 2955 01 背包 Robberies

题意:

       好多个银行,他们很有钱。有个人想去抢劫。告诉你银行的钱和抢这个银行被抓的概率。银行被你抢一次就会没钱。现在需要你满足的条件是被抓的概率小于他给的stand,问,最多能得到多少钱。

做题过程:

      这是一道很有现实主义色彩,很实用的一道题。总共就n个银行,他们钱数就是背包的容量,每个银行只抢一次,由此看出是个01背包,背包出的价值(概率)最大。开始我还以为要dp出个最小呢。现在想想,应该是在获得钱数尽可能多的情况下求最大逃脱概率才对。

      状态转移方程:d[money] = max( d[money - m[i]] * (1 - p[i] ) ). d[money]就是获得money的最大逃脱概率。

      其中,为什么不能求最小被抓概率呢?因为求不出来。最小被抓概率= 其中一个被抓 || 其中两个被抓。。。。|| 全被抓了。所以,高数告诉我们,从反面考虑。

      其次,这里一个优化是用sum记录前几个的钱之和(体积和),因为即使前面几个都放进去,也不会超过那个容量的。

      最后,我表示疑惑,传说中的01背包不是要从后往前for的吗?我从后往前给wa了。难道,从后往前的意思是代码中的第二个for。我咋记得重要一个for就行了,为什么这题是两个for呢。         第一道01背包题!WA了几次。。。

/*
Pro: 0

Sol:

date:
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <set>
#include <vector>
#define maxn 120
using namespace std;
int m[maxn],t,n,sum[maxn];
double p[maxn],stand,d[maxn * maxn];
int main(){
    scanf("%d",&t);
    while(t --){
        scanf("%lf%d",&stand,&n);
        sum[0] = 0;
        for(int i = 1; i <= n;i ++){
            scanf("%d%lf",&m[i],&p[i]);//被抓的概率
            sum[i] = sum[i - 1] + m[i];
        }
        memset( d, 0,sizeof(d));  d[0] = 1;//不抢钱,被抓的概率为1
        for(int i = 1; i <= n; i ++){
            for(int j = sum[i]; j >= m[i]; j --){
                d[j] = max(d[j],d[j - m[i]] * (1 - p[i]));//逃脱的概率,取最大的
            }
        }
        for(int i = sum[n]; i >= 0; i --)//必须是大于等于0,而不是1,可以不抢钱
            if(d[i] > 1 - stand){
                printf("%d\n",i) ; break;
            }

    }
    return 0;
}


你可能感兴趣的:(hdu 2955 01 背包 Robberies)