Robberies HDU - 2955
点击跳转↑
- 题设:T为样例数,对于每个样例,给定P和N,分别表示小偷在偷了数个银行后,若被抓的总概率低于P他可以完美脱身,和一共可以偷的银行数量。接下来N行,每行两个值m[ i ]和p[ i ],分别代表一个银行可以偷到的钱,和偷了之后会被抓的概率(不同银行相互独立,总概率等于多个概率相乘)。问:在不被抓的情况下,最大能偷的金钱量。
- 思路:很明显这是一个01背包问题,但是——
01背包问题牵扯到两个基本的属性: 容量和价值, 如果直观的照搬01背包问题的话, 那么容量和价值应该是概率和钱数.
但因为概率是一个浮点数, 而且题目也没有给定最小是几位小数(预计九位,将概率先扩大再照搬普通01背包,在遍历更新必超时), 所以无法遍历。
那么就只能把容量定义为可得到的金钱, dp[ i ] 即为安全的概率, 题中给出的是被抓的概率, 但因为如果用被抓的概率在初始化上会有些麻烦, 所以干脆定义为不被抓, 也就是安全的概率反而比较简单.
所以数据特殊处理:P=1-P,p【i】=1-p【i】。
状态转移方程和初始化:
(dp【v】表示偷得价值为 v 的金钱时不被抓的概率)
- dp【0】= 1(表示价值为0时小偷必定不被抓)
- dp【j】 = max( dp【j】 , dp【j-m【i】】 * p【i】 )
代码:
#include<bits/stdc++.h>
#define ll long long
#define SC(a) scanf("%d",&a)
#define mem(a,n) memset(a,n,sizeof(a))
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
priority_queue <int,vector<int>,less<int> > QM;
const int INF= 0x3f3f3f3f;
const int maxn= 2e5+5;
const double eps= 1e-9;
int m[maxn],Mbag;
double p[maxn],dp[maxn];
int main()
{
IOS;
int t;
cin>>t;
while(t--)
{
double P,N;
cin>>P>>N;
//数据处理
P = 1-P;
Mbag=0;
for(int i=1;i<=N;i++)
{
cin>>m[i]>>p[i];
Mbag += m[i];
p[i] = 1-p[i];
}
//初始化
dp[0] = 1;
for(int i=1;i<=Mbag;i++) dp[i]=0;
//01背包
for(int i=1;i<=N;i++)
{
for(int j=Mbag;j>=m[i];j--)
dp[j] = max(dp[j],dp[j-m[i]]*p[i]);
}
//逆向遍历取得最大结果
for(int i=Mbag;i>=0;i--)
if(dp[i]-P >= eps)//精度
{
cout<<i<<endl;
break;
}
}
return 0;
}