题意:Roy打算抢劫银行。有N个银行,每个银行有存款Mi,和被抢劫后抓住的概率Pi。不同银行被抓的概率是独立的。现在Roy希望将自己被抓的概率控制在P以下的同时,让自己抢劫到尽可能多的钱。
思路:因为对于每个银行的决策只有两种选项:抢与不抢,所以这是个01背包。相对于被抓的概率,逃脱的概率更好求,最后我们只需1-逃脱的概率即可。
但是因为概率是个小数,我们没法用其表示状态:在某个概率小,能抢到的最多钱。所以,我们要将抢到的钱作为下标,从而将DP的状态定义为:在抢得i万元钱时,能逃脱的最大概率。
最后,我们只需线性的扫一遍,找出最大的i,使dp[i]大于等于最终的逃脱概率就行。
注意:题目中给的样例有很大的迷惑性。刚开始读题把题意读错了,以为只是普通的求和。没有看到概率。
代码如下:
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
const double INF = 0x3f3f3f3f;
const double EPS = 1e-6;
int v[110];
double dv,dw[110],dp[10010];
int dcmp(double x)
{
if(fabs(x) < EPS)
return 0;
else if(x < 0)
return -1;
else
return 1;
}
int main(void)
{
//freopen("input.txt","r",stdin);
int T,N;
scanf("%d",&T);
while(T--){
scanf("%lf%d",&dv,&N);
int sum = 0;
for(int i = 0; i < N; ++i){
scanf("%d%lf",v+i,dw+i);
dw[i] = 1.0 - dw[i];
sum += v[i];
}
memset(dp,0,sizeof(dp));
dp[0] = 1;
for(int i = 0; i < N; ++i)
for(int j = sum; j >= v[i]; --j)
dp[j] = max(dp[j],dp[j-v[i]] * dw[i]);
for(int i = sum; i >= 0; --i){
if(dcmp(dp[i] - 1.0 + dv) >= 0){
printf("%d\n",i);
break;
}
}
}
return 0;
}