01背包-Robberies

本文探讨了一种经典的动态规划问题——银行抢劫问题。通过分析案例,介绍了如何使用动态规划求解最大收益的同时确保被抓概率低于给定阈值。文章还对比了不同解法,并给出了详细的实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

E - Robberies
Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u

Description

The aspiring Roy the Robber has seen a lot of American movies, and knows that the bad guys usually gets caught in the end, often because they become too greedy. He has decided to work in the lucrative business of bank robbery only for a short while, before retiring to a comfortable job at a university. 

For a few months now, Roy has been assessing the security of various banks and the amount of cash they hold. He wants to make a calculated risk, and grab as much money as possible. 


His mother, Ola, has decided upon a tolerable probability of getting caught. She feels that he is safe enough if the banks he robs together give a probability less than this.
 

Input

The first line of input gives T, the number of cases. For each scenario, the first line of input gives a floating point number P, the probability Roy needs to be below, and an integer N, the number of banks he has plans for. Then follow N lines, where line j gives an integer Mj and a floating point number Pj . 
Bank j contains Mj millions, and the probability of getting caught from robbing it is Pj .
 

Output

For each test case, output a line with the maximum number of millions he can expect to get while the probability of getting caught is less than the limit set. 

Notes and Constraints 
0 < T <= 100 
0.0 <= P <= 1.0 
0 < N <= 100 
0 < Mj <= 100 
0.0 <= Pj <= 1.0 
A bank goes bankrupt if it is robbed, and you may assume that all probabilities are independent as the police have very low funds.
 

Sample Input

       
3 0.04 3 1 0.02 2 0.03 3 0.05 0.06 3 2 0.03 2 0.03 3 0.05 0.10 3 1 0.03 2 0.02 3 0.05
 

Sample Output

       
2 4 6
 

英语不好做题永远是硬伤啊。题目大意是:先给出两个数字p和num,p代表被抓的机率,num代表银行数,每个银行都有mi和pi,mi是银行的金额,pi是偷该银行被抓的概率。该题目要求在不被抓的情况下偷到最大的钱。相当于偷银行时,pi之和要小于p。

这题目我觉得有两种解法的

1,网上普遍的解法是将被抓的机率变为幸存的机率,用01背包,dp[i]中,dp存放的是当偷取金额i时候的幸存几率,最后从最大金额向低处遍历,只要dp中的机率,即幸存机率,大于一开始设定的p即可。

2,直接正面去做,保证pi之和小于p。这里又分两种情况,①,dp[i]中存放的是金额,最后从最大金额开始向低处遍历,运用回溯,来确定某个银行是否被偷,将机率加起来,和一开始给的p进行比较。②,dp[i]中存放的是被抓机率,i代表金额,金额越高被抓机率也越高。最后运用回溯,先比较dp[i]是否小于p,如果小于,开始判断哪些银行被偷过。

方法2要写很长的代码,特别是回溯部分,需要用到栈,所以我一开始没去搜题解,导致用方案2.①时,TLE了。用2.②时,超内存了。说白了方法2根本没用到动态规划,只用了01背包那种打表方式,它需要每个都返回去寻找并且判断,这说白了就是暴力,炸了是妥妥的。

代码如下:

#include<iostream>
#include<cstdio>
using namespace std;
#define max(a,b) a>b?a:b

int main()
{
	int t,num,money[105],sum;
	double pro[105],p;
	scanf("%d",&t);
	while(t--)
	{
		double dp[10005]={1.0};
		scanf("%lf%d",&p,&num);
		sum=0;
		for(int i=0;i<num;i++)
		{
			scanf("%d%lf",&money[i],&pro[i]);
			sum+=money[i];
		}
		for(int i=0;i<num;i++)
		{
			for(int j=sum;j>=money[i];j--)
			{
				dp[j]=max(dp[j-money[i]]*(1-pro[i]),dp[j]);
			}
		}
		for(int i=sum;i>=0;i--)
		{
			if(dp[i]>=1-p)
			{
				printf("%d\n",i);
				break;
			}	
		}
	}
}

我还是比较反对用#define的,特别是其中的内容要运用多次时候,他要不断向系统申请内存,导致效率很低。用函数代替就好多了。

这道题目调试的时候发现,浮点数读入后,很多值都不是题目给的值,比如0.04读入后变成了0.03999999997之类的,最后判断的时候,编译器有他自己一套判断体系吧,所以就不管了,当成精确的写。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值