题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=2955
题目大意:
有个人要去抢劫银行,在这之前他对自己抢劫的行为进行了风险估计,抢不同的银行获得的前不同风险也不同。抢银行时他有一个最高风险的上限,现在问在不超过最高风险的情况下(不被抓),他最多能抢多少钱。
思路:
题目给了两个变量,风险指数和价值,很容易想到就是01背包。
如果我们把风险当做容量,抢一个银行的钱当做价值,只要算出最大风险以内获得的最大价值。
但是风险是float型浮点数,我们放不到数组里面去。如果考虑将浮点数化为整数,float型精确值有7位有效数字,这样放大的话,数组也开不下。
最重要的是!我抢两个银行,风险不是单纯的相加!
这是我最初犯的错误= =。。。。
所以先分析一下,抢多个银行时候的风险计算:如果假设我只抢两个银行,被抓的概率分别为a,b。抢完以后,有3种情况:1、同时被两个银行抓。2、被其中一个银行抓。3、没有银行抓我。我要考虑的,只是前两个情况。所以我的风险就是1-P(3)。
P(3)就是没有银行抓我,那么我不被两个银行抓的概率分别是1-a和1-b,两者同时发生的概率就是P(3)=(1-a)*(1-b)。
所以我的风险就是1-P(3)。
-----------------------------------------------------------------------------------------------------------------------------------------------------
再重新考虑问题的求解:既然不能把风险当容量,我就尝试把抢来的钱的总和当做容量,风险当做价值。
此时我要做的就是:求出当前抢到的钱的最小被抓风险。
所以我设一个dp[ j ],代表价值为j时的最小被抓概率。这里最小的被抓概率==最大的逃脱概率,所以可以替代掉。
最后我找到那个风险小于最大上限的价值即可。
代码:
#include<stdio.h>
#include<string.h>
#include<math.h>
double max(double a,double b)
{
if(a>b)return a;
else return b;
}
struct node {
int m;
double p;
}a[105];
double dp[10005];
int main()
{
int T,i,k,N,x,j;
double P;
scanf("%d",&T);
while(T--)
{
int sum=0;
memset(dp,0,sizeof(dp));
scanf("%lf%d",&P,&N);
x=1;
for(i=1;i<=N;i++)
{
scanf("%d%lf",&a[i].m,&a[i].p);
sum+=a[i].m;
a[i].p=1-a[i].p;
}
dp[0]=1; //初始化,没有抢的时候被抓风险为0.
for(i=1;i<=N;i++)
for(j=sum;j>=a[i].m;j--)
{
dp[j]=max(dp[j],dp[j-a[i].m]*a[i].p);
}
printf("%d\n",j);
}
return 0;
}
/*
5
0.45 3
1 0.255
2 0.145
3 0.051
*/