HDU 2955 Robberies(概率DP,01背包)题解
题意:给出规定的最高被抓概率m,银行数量n,然后给出每个银行被抓概率和钱,问你不超过m最多能拿多少钱
思路:一道好像能直接01背包的题,但是有些不同。按照以往的逻辑,dp[i]都是代表i代价能拿的最高价值,但是这里的代价是小数,显然不能这么做。还有,被抓概率显然不能直接相加,也不能相乘(越乘越小),这里就需要一些转化。我们把被抓概率转化为逃跑概率也就是1-被抓,那么逃跑概率就能直接相乘了。dp[i]代表拿到i价值的最大逃跑概率,这样又变成了01背包。最后求逃跑概率大于等于1-m的最大的钱。
代码:
#include<cstdio> #include<set> #include<map> #include<cmath> #include<stack> #include<vector> #include<queue> #include<cstring> #include<string> #include<sstream> #include<iostream> #include<algorithm> #define ll long long using namespace std; const int maxn = 10000+10; const int INF = 0x3f3f3f3f; double dp[maxn]; //逃跑概率 int val[105]; double pr[105]; int main(){ int T; scanf("%d",&T); while(T--){ double need; int n,sum = 0; scanf("%lf%d",&need,&n); need = 1 - need; for(int i = 1;i <= n;i++){ scanf("%d%lf",&val[i],&pr[i]); sum += val[i]; pr[i] = 1 - pr[i]; } memset(dp,0,sizeof(dp)); dp[0] = 1; for(int i = 1;i <= n;i++){ for(int j = sum;j >= val[i];j--){ dp[j] = max(dp[j],dp[j - val[i]]*pr[i]); } } int ans = 0; for(int i = sum;i >= 0;i--){ if(dp[i] >= need){ ans = i; break; } } printf("%d\n",ans); } return 0; }