HDU2955 01背包变体 xingxing在努力

  这道题的题意是小偷要去偷N家银行, 每家银行都有一个钱款数额Mi和被抓概率pi, 求小偷被抓的概率小于P的情况下所能偷到的钱数额的最大值(每家银行最多偷一次),由于每家银行最多偷一次, 所以这个题可以用01背包的思想来求解, 又因为小偷被抓会有很多种情况,并不好算,因此我们用他的反面小偷成功逃脱来算?这样题目就成了小偷在成功逃脱的概率大于1-P的情况下所能偷到的钱数最大值。。记f[i][j]为小偷在前i家银行恰好偷了j块钱成功逃脱的 概率最大值, 那么f[i][j] = max(f[i-1][j], f[i-1][j-W[i]]*(1-Pi[i])),该过程可以使滚动数组优化:代码如下:

#include <cstdio>
#include <algorithm>
#include <cstring>

using namespace std;
const double inf = 100000000000000;
const double eps = 1e-12;
int Mi[100 + 10];
double Pi[100 + 10];
double f[10000 + 100];
double P;
int N;

int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%lf%d", &P, &N);
        P = 1 - P;
        int sum = 0;
        for(int i=1; i<=N; i++)
        {
            scanf("%d%lf", &Mi[i], &Pi[i]);
            sum += Mi[i];
        }
        for(int i=1; i<=sum; i++) f[i] = -inf;
        f[0] = 1;    //刚开始抢了0家银行, 逃脱概率为1
        int res = 0;
        for(int i=1; i<=N; i++)
        {
            for(int j=sum; j>=Mi[i]; j--)
            {
                f[j] = max(f[j], f[j-Mi[i]]*(1-Pi[i]));
                if(f[j]-P >= 0)
                    res = max(res, j);
            }
        }
        printf("%d
", res);
    }
    return 0;
}