题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2955
这是一道01背包的变体,
题目大意:有个人去抢劫银行,已知最大风险指数,想要成功逃跑,风险必须控制在小于或等于这个风险内,并且知道各银行所存的钱及各银行被抓的风险,求在成功逃跑的情况下所能抢到最多的钱是多少?
0< T <= 100 测试案例个数
0.0 <= P <= 1.0 最大风险指数
0 < N <= 100 银行的数量
0 < Mj <= 100 各银行所拥有的钱
0.0 <= Pj <= 1.0 抢劫各银行被抓的风险指数
解析:顺着题意做非常困难,需要转换思维,把最大风险指数改成最小逃跑所需指数,各银行的被抓指数也改成能逃跑的指数pi=1-pi,因此想要成功逃跑,总逃跑指数必须大于或等于最小逃跑所需指数,因为逃跑是独立事件,所以总逃跑指数=各逃跑成功指数相乘(我理解了好久才搞懂,重要!),在dp过程中设钱的数量为背包容量的大小,
dp方程:
dp[j]=max(dp[j],dp[j-pe[i].mj]*pe[i].pj);
详细解释看代码:
#include <iostream>
#include<cstdio>
#include<cstring>
using namespace std;
struct node
{
int mj;//记录每所银行拥有的钱
double pj;//记录抢劫每所银行被抓的风险
}pe[105];
int main()
{
int t;
scanf("%d",&t);
double dp[10005];//最多会抢到的钱数=最多银行数*每家银行最多拥有的钱数=10000
while(t--)
{
memset(dp,0,sizeof(dp));//当抢到的的钱数为0时逃跑概率为1
dp[0]=1;//其余均设逃跑概率为0
double p;//最大风险指数
int n;//银行数量
int sum=0;//所用银行拥有的钱数
scanf("%lf %d",&p,&n);
for(int i=0;i<n;i++)
{
scanf("%d %lf",&pe[i].mj,&pe[i].pj);
sum=sum+pe[i].mj;
pe[i].pj=1-pe[i].pj;//抢劫各银行被抓的风险指数转化成逃跑的指数
}
int ans;
for(int i=0;i<n;i++)
for(int j=sum;j-pe[i].mj>=0;j--) //银行抢劫的越多能逃跑的概率越低,所以求在
dp[j]=max(dp[j],dp[j-pe[i].mj]*pe[i].pj);//抢劫相同钱的情况下所能逃跑的最大概率
for(int i=sum;i>=0;i-- )//找出可以成功逃走并且逃走概率不超过警戒值
if(dp[i]>=1-p)//最小逃跑所需指数为1-p
{
ans=i;//抢到的钱的数量
break;
}
printf("%d\n",ans);
}
return 0;
}
在