标签:01背包
hdu2955 http://acm.hdu.edu.cn/showproblem.php?pid=2955
题意:盗贼抢银行,给出n个银行,每个银行有一定的资金和抢劫后被抓的概率,在给定一个概率P,表示盗贼愿意冒险抢劫所能承受的最大被抓概率。
思路:首先用1减去被抓概率,得到安全概率。那抢劫了多家银行后的安全概率就是这些银行各自的安全概率连乘起来。其实是01背包的变种,
dp[j] 表示获得金额 j 时的安全概率。这里用滚动数组,得方程 dp[j] = max(dp[j], dp[i-a[i]]*(1-b[i]) 其中a表示银行金额,b表示被抓概率。
trick:概率的精度不总是2
自WA点: 滚动数组的 j 要逆序遍历。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <map>
#include <utility>
#include <queue>
#include <stack>
#define N 105
#define REP(i,n) for(i=0;(i)<(n);i++)
using namespace std;
const int INF=<<;
const double eps=1e-; double dp[N*N],b[N];
int n,a[N]; void run()
{
int _;
scanf("%d",&_);
while(_--)
{
int sum=,i,j;
double p;
memset(dp,,sizeof(dp));
cin>>p>>n;
REP(i,n)
{
cin>>a[i]>>b[i];
sum+=a[i];
}
dp[]=1.0;
REP(i,n)
for(j=sum;j>=a[i];j--)
{
dp[j]=max(dp[j],dp[j-a[i]]*(1.0-b[i]));
}
for(i=sum;i>=;i--)
if(dp[i]>=1.0-p)
{
cout<<i<<endl;
break;
}
}
} int main()
{
// freopen("case.txt","r",stdin);
run();
return ;
}