题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2955 RobberiesTime Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Problem Description
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 . 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.
|
解题思路
这题很容易想成:以最大被抓概率为背包最大容量,将银行作为商品,抢一个银行的被抓概率为商品体积,银行里的钱为商品价格。 这有两个问题:①被抓概率为浮点数,且不知道小数点后几位(double16位必然爆内存)无法开数组;②被抓概率不是简单的相加,(因为你第一次逃掉的概率为A,第二次逃掉的概率为B,那么两次都逃掉的概率是A*B不是A+B)。
那么我们不妨以所有银行的钱数总和为背包最大容量,以抢某个银行的钱作为商品体积,以抢完(后)这个银行后的逃跑概率作为商品价值(背包模型中数组的值代表能得到的最大价值,这里数组的值代表能跑掉的最大概率 )。那么我们从小到大枚举背包容量(钱),当商品价值(逃跑概率)大于最小逃跑概率时,所对应的背包容量(钱)就是可以得到的最优解(能抢的最多钱)。
AC代码
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
struct bank {
double w;
int c;
}b[101];
double escape[10005]; //当抢了i元时的逃跑概率
int main()
{
int T,N;
double P;
cin >> T;
while( T--)
{
cin >> P >> N;
int sum=0; //所有银行的钱
for(int i=0;i<N;i++) {
cin >> b[i].c >> b[i].w;
sum += b[i].c;
}
memset(escape,0,sizeof escape); //刚开始认为只要抢了钱,你就跑不掉
escape[0] = 1; //啥都没抢凭啥抓你?所以逃跑概率当然是1啦
for(int i=0;i<N;i++)
for(int j=sum;j>=b[i].c;j--) //抢你一块钱或者把你的钱都抢了你都要抓我,对强盗来说当然要全抢才可能是最优解
escape[j] = max(escape[j],escape[j-b[i].c]*(1-b[i].w)); //多种抢钱方法得到的钱一样,我当然去抢逃跑概率大的那种
for(int i=sum;i>=0;i--)
if(escape[i] > double(1-P)) { //再多抢就跑不掉了
cout << i << endl;
break;
}
}
}