您的位置:首页 > 其它

hdu 2955 01 背包 Robberies

2012-08-24 08:56 239 查看
题意:

好多个银行,他们很有钱。有个人想去抢劫。告诉你银行的钱和抢这个银行被抓的概率。银行被你抢一次就会没钱。现在需要你满足的条件是被抓的概率小于他给的stand,问,最多能得到多少钱。

做题过程:

这是一道很有现实主义色彩,很实用的一道题。总共就n个银行,他们钱数就是背包的容量,每个银行只抢一次,由此看出是个01背包,背包出的价值(概率)最大。开始我还以为要dp出个最小呢。现在想想,应该是在获得钱数尽可能多的情况下求最大逃脱概率才对。

状态转移方程:d[money] = max( d[money - m[i]] * (1 - p[i] ) ). d[money]就是获得money的最大逃脱概率。

其中,为什么不能求最小被抓概率呢?因为求不出来。最小被抓概率= 其中一个被抓 || 其中两个被抓。。。。|| 全被抓了。所以,高数告诉我们,从反面考虑。

其次,这里一个优化是用sum记录前几个的钱之和(体积和),因为即使前面几个都放进去,也不会超过那个容量的。

最后,我表示疑惑,传说中的01背包不是要从后往前for的吗?我从后往前给wa了。难道,从后往前的意思是代码中的第二个for。我咋记得重要一个for就行了,为什么这题是两个for呢。 第一道01背包题!WA了几次。。。
/*
Pro: 0

Sol:

date:
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <set>
#include <vector>
#define maxn 120
using namespace std;
int m[maxn],t,n,sum[maxn];
double p[maxn],stand,d[maxn * maxn];
int main(){
scanf("%d",&t);
while(t --){
scanf("%lf%d",&stand,&n);
sum[0] = 0;
for(int i = 1; i <= n;i ++){
scanf("%d%lf",&m[i],&p[i]);//被抓的概率
sum[i] = sum[i - 1] + m[i];
}
memset( d, 0,sizeof(d));  d[0] = 1;//不抢钱,被抓的概率为1
for(int i = 1; i <= n; i ++){
for(int j = sum[i]; j >= m[i]; j --){
d[j] = max(d[j],d[j - m[i]] * (1 - p[i]));//逃脱的概率,取最大的
}
}
for(int i = sum
; i >= 0; i --)//必须是大于等于0,而不是1,可以不抢钱
if(d[i] > 1 - stand){
printf("%d\n",i) ; break;
}

}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: