(01背包)hdu 2955 Robberies

题目
hdu2955

题意:
给出 n 家银行的金额和被抓的概率,求出不超出被抓概率 p 的最大抢劫金额。

思路:
如果把被抓概率看成背包容量进行dp,则wa,
这里犯了一个常识的错误,被抓概率 = 被抓概率1 + 被抓概率2,其实这是错的。

举个例子,某彩票的中奖概率是50%,按照上面的计算方法(中奖概率 = 中奖概率1 + 中奖概率2),那么买两张彩票则必中奖(两张彩票中奖概率 = 50% + 50% = 100%),这是不科学的。

实际上两张彩票中奖概率为75%(两张彩票中奖概率 = 第一张中第二张不中 + 第一张不中第二张中 + 两张都中 => 第一张中奖概率 * 第二张不中奖概率 + 第一张不中奖概率 * 第二张中奖概率 + 第一张中奖概率 * 第二张中奖概率 = 50% * 50% + 50% * 50% + 50% * 50% = 75%)

回到题目,也就是说,
被抓概率 = 第一家银行被抓概率 * 第二家银行不被抓概率 + 第一家银行不被抓概率 * 第二家银行被抓概率 + 第一家银行被抓概率 * 第二家银行被抓概率 => 1 - 第一家银行不被抓概率 * 第二家银行不被抓概率

因为被抓概率不是线性的,所有要把金额看成背包容量进行dp,dp数组记录的是不被抓的最大概率。

代码

#include <bits/stdc++.h>
#define DEBUG freopen("_in.txt", "r", stdin); freopen("_out1.txt", "w", stdout);
#define CASE int t; cin >> t; while (t--)
using namespace std;
const int MAXN = 110;
const int MAXM = 1e4 + 10;
int v[MAXN];
double dp[MAXM], b[MAXN];
void solve(){
    
    
	int n, tot = 0;
	double p;
	scanf("%lf%d", &p, &n);
	for (int i = 0; i < n; i++){
    
    
		scanf("%d%lf", &v[i], &b[i]);
		b[i] = 1 - b[i];
		tot += v[i];
	}
	memset(dp, 0, sizeof(dp));
	dp[0] = 1;  //一开始当然不会被抓
	double temp;
	for (int i = 0; i < n; i++)
		for (int j = tot; j >= v[i]; j--)
			dp[j] = max(dp[j], dp[j-v[i]] * b[i]);
	for (int i = tot; i >= 0; i--)
		if (1 - dp[i] <= p){
    
      //输出不被抓的最大金额
			printf("%d\n", i);
			break;
		} 
} 
int main(){
    
    
	CASE solve(); 
	return 0;
}

猜你喜欢

转载自blog.csdn.net/ymxyld/article/details/113744959