概率dp hdu2599

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.

 

Input

The first line of input gives T, the number of cases. For each scenario, the first line of input gives a floating point number P, the probability Roy needs to be below, and an integer N, the number of banks he has plans for. Then follow N lines, where line j gives an integer Mj and a floating point number Pj . 
Bank j contains Mj millions, and the probability of getting caught from robbing it is Pj .

 

Output

For each test case, output a line with the maximum number of millions he can expect to get while the probability of getting caught is less than the limit set. 

Notes and Constraints 
0 < T <= 100 
0.0 <= P <= 1.0 
0 < N <= 100 
0 < Mj <= 100 
0.0 <= Pj <= 1.0 
A bank goes bankrupt if it is robbed, and you may assume that all probabilities are independent as the police have very low funds.

 

Sample Input

 

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

 

Sample Output

 

2 4 6

这道题我一眼看,这不就是个01背包的板子吗,后来发现概率不能相加。。。。。。

我看了好久的题目:发现这被抓的概率越乘越小是什么鬼,偷得越多还越难抓了?但是反过来想就很容易理解了,

第一个样例给出了要小于0.04的风险,那么我们逃跑的概率就最少0.96,我们在下面的计算中只需要保证我们逃跑概率大于0.96就行了.

但是这里有个问题,我们在写01背包的时候,dp[j]这里面的j表示的当前背包的容量,dp[j]表示的当前的最大价值,要是换成这道题我们的惯性思维就是把概率当成背包容量,由于数组的下标不能为浮点,所以我们只能反过来.    dp[j]表示在价值为j时逃跑概率的最大值就完美的解决了.

状态转移:

for(int i = 1; i <= n; i++){//从第一个银行开始遍历
        for(int j = sum; j >= val[i]; j--){//假设已经偷了第i个银行
            double k = (1 - w[i] * 1.0) * dp[j - val[i]];//偷了第i个银行,剩余价值j - val[i]
            dp[j] = max(dp[j],k);
        }
      }

下面是ac代码

#include <queue>
#include <cstdio>
#include <set>
#include <string>
#include <stack>
#include <cmath>
#include <climits>
#include <map>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <stdio.h>
#include <ctype.h>
#include <bitset>
#define  LL long long
#define  ULL unsigned long long
#define mod 10007
#define INF 0x7ffffff
#define mem(a,b) memset(a,b,sizeof(a))
#define MODD(a,b) (((a%b)+b)%b)
using namespace std;
const int maxn = 100010;
int n,m,cnt;
int val[maxn];
double w[maxn];
double dp[maxn];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
      double V;
      int n;
      int sum = 0;
      scanf("%lf%d",&V,&n);
      for(int i = 1; i <= n; i++){
        scanf("%d%lf",&val[i],&w[i]);
        sum += val[i];
      }
      V = 1 - V;
      mem(dp,0);
      dp[0] = 1;
      for(int i = 1; i <= n; i++){
        for(int j = sum; j >= val[i]; j--){
            double k = (1 - w[i] * 1.0) * dp[j - val[i]];
            dp[j] = max(dp[j],k);
        }
      }
      int ans = 0;
      //printf("%f\n",dp[sum]);
      for(int i = sum; i >= 0; i--){//找一个最大的i,满足要求就行了
        if(dp[i] > V){
            ans = i;
            break;
        }
      }
      printf("%d\n",ans);
    }




    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值