HDU 2955|Robberies|01背包|概率

Problem Description

The aspiring Roy the Robber has seen a lot of American movies, and knows that the bad guys usually gets caught in the end, often because they become too greedy. He has decided to work in the lucrative business of bank robbery only for a short while, before retiring to a comfortable job at a university.

For a few months now, Roy has been assessing the security of various banks and the amount of cash they hold. He wants to make a calculated risk, and grab as much money as possible.

His mother, Ola, has decided upon a tolerable probability of getting caught. She feels that he is safe enough if the banks he robs together give a probability less than this.

题目翻译(个人翻译仅供参考)

Roy是一个有抱负的强盗(-_-),看了很多美国大片,知道了坏蛋因为太过贪心,最终的结果通常是被捕。他决定做一次合算的买卖:在大学毕业之前,快速地搞一次大新闻:bank robbery(请自行体会)。
几个月过去了,Roy已经完成了对N个银行的安全性和拥有的货币的数量的评估。他希望计算行动的风险,并且拿走尽可能多的钱。
它的母亲Ola知道了Roy能承受的被捕的最大概率P,她认为如果Roy实施行动被捕的概率如果低于这个能承受的最大概率,Roy就是安全的。

Robberies

你可以认为不同银行间的概率是独立互不影响的,因为一间银行被盗后就倒闭了,然后警方也没有多少资金。

输入

第一行一个整数 T(0<T100) ,表示数据组数。
接下来对于每组数据,第一行有2个数:浮点数 P(0P1) 和整数 N(0<N100)
接下来N行,每行有2个数: mj(0<mj100) pj(0pj1) ,分别表示第j个银行拥有的货币数量和对该银行实施行动被捕的概率。

输出

对于每组数据输出一行一个整数,表示Roy安全的情况下能拿到的最多的钱有多少。

样例输入

3
0.04 3
1 0.02
2 0.03
3 0.05

0.06 3
2 0.03
2 0.03
3 0.05

0.10 3
1 0.03
2 0.02
3 0.05

样例输出

2
4
6

题解

注意到M很小,只有100,然后 N×M 也只有10000,也就是所有银行的总价值不超过10000,我们就可以用选中银行总价值表示状态了。
dp[i,j]表示目前已经考虑到第i个银行了,选中银行价值为j时的最大的安全概率是多少。然后计算出所有的dp[n]后我们选出最大的j(即结果)使得dp[n,j]>P即可。
状态转移方程也很显然:dp[i,j]=max(dp[i-1,j],dp[i-1,j-m[i]]*p[i]),借用了01背包的转移方程,另外这里的p[i]也是安全概率。
因为安全的概率可以乘,但被捕的概率综合是不可以的。

#include <cstdio>
#include <cstring>
#include <algorithm>
#define FOR(i,j,k) for(i=j;i<=k;++i)
using namespace std;
const int N = 105;
int m[N];
double dp[N * N], p[N];
int main() {
    int t, i, j, n, sum;
    double P;
    scanf("%d", &t);
    while (t--) {
        scanf("%lf%d", &P, &n);
        P = 1 - P;
        memset(dp, 0, sizeof dp);
        dp[0] = 1;
        sum = 0;
        FOR(i,1,n) {
            scanf("%d%lf", &m[i], &p[i]);
            p[i] = 1 - p[i];
            sum += m[i];
        }
        FOR(i,1,n)
            for (j = sum; j >= m[i]; --j)
                dp[j] = max(dp[j], dp[j - m[i]] * p[i]);
        for (j = sum; j >= 1; --j)
            if (dp[j] > P)
                break;
        printf("%d\n", j);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值