HDU 2955 Robberies(概率DP,01背包)题解

题意:给出规定的最高被抓概率m,银行数量n,然后给出每个银行被抓概率和钱,问你不超过m最多能拿多少钱

思路:一道好像能直接01背包的题,但是有些不同。按照以往的逻辑,dp[i]都是代表i代价能拿的最高价值,但是这里的代价是小数,显然不能这么做。还有,被抓概率显然不能直接相加,也不能相乘(越乘越小),这里就需要一些转化。我们把被抓概率转化为逃跑概率也就是1-被抓,那么逃跑概率就能直接相乘了。dp[i]代表拿到i价值的最大逃跑概率,这样又变成了01背包。最后求逃跑概率大于等于1-m的最大的钱。

代码:

#include<cstdio>
#include<set>
#include<map>
#include<cmath>
#include<stack>
#include<vector>
#include<queue>
#include<cstring>
#include<string>
#include<sstream>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn = 10000+10;
const int INF = 0x3f3f3f3f;
double dp[maxn];    //逃跑概率
int val[105];
double pr[105];
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        double need;
        int n,sum = 0;
        scanf("%lf%d",&need,&n);
        need = 1 - need;
        for(int i = 1;i <= n;i++){
            scanf("%d%lf",&val[i],&pr[i]);
            sum += val[i];
            pr[i] = 1 - pr[i];
        }
        memset(dp,0,sizeof(dp));
        dp[0] = 1;
        for(int i = 1;i <= n;i++){
            for(int j = sum;j >= val[i];j--){
                dp[j] = max(dp[j],dp[j - val[i]]*pr[i]);
            }
        }
        int ans = 0;
        for(int i = sum;i >= 0;i--){
            if(dp[i] >= need){
                ans = i;
                break;
            }
        }
        printf("%d
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/KirinSB/p/9491693.html