HDU - 2955 Robberies【动态规划 01背包】

版权声明:文章原创,未经允许请勿转载 https://blog.csdn.net/DanBo_C/article/details/89889660

Robberies

译文:

问题描述
有抱负的Roy the Robber已经看过很多美国电影,并且知道坏人通常最终会被抓到,通常是因为他们变得过于贪婪。在退休到大学舒适的工作之前,他决定只在短时间内从事利润丰厚的银行抢劫业务。

几个月以来,罗伊一直在评估各家银行的安全性以及他们持有的现金数量。他想要计算风险,并尽可能多地赚钱。

他的母亲奥拉已经决定了被抓住的可能性。如果他一起抢劫的银行给出的概率低于此值,她觉得自己足够安全。

输入
第一行输入给出T,即案例数。对于每个场景,第一行输入给出浮点数P,Roy需要低于的概率,以及整数N,即他计划的银行数。然后遵循N行,其中行j给出整数Mj和浮点数Pj。
银行j包含Mj百万,并且被抢劫的可能性是Pj。

产量
对于每个测试用例,输出一条线,其中可以获得的最大数量为百万,而被捕获的概率小于设定的限制。

注释和约束
0 <T <= 100
0.0 <= P <= 1.0
0 <N <= 100
0 <Mj <= 100
0.0 <= Pj <= 1.0
如果银行被抢劫银行破产,你可能会认为所有由于警方资金很少,概率是独立的。

样本输入
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

样本输出
2
4
6

解题思路:

一个很典型的动态规划背包问题

  1. 先从题中给的测试点中截取一部分分析

    1
    0.04 3
    1 0.02
    2 0.03
    3 0.05

  2. 分析:
    N(案例)= 1
    P(不被抓到) = 0.04
    n(银行)= 3
    n(第0个银行抢劫金额)= 1
    P(被第0个银行抓到) = 0.02
    n(第1个银行抢劫金额)= 2
    P(被第1个银行抓到) = 0.03
    n(第2个银行抢劫金额)= 3
    P(被第2个银行抓到) = 0.05

  3. 方法一:暴力搜索(时间复杂度高)

  4. 方法二:记忆搜索(多于部分样例,有可能超时)

  5. 方法三:动态规划,背包问题(时间复杂度低)

  6. 因为需要尽可能多的抢劫,那么dp数组就反着算。针对样例来说,可以抢劫的可能有1,2,3(3 /(1+2)),4(1+3),5(2+3),6(1+2+3).那么dp数组就先算dp[6],dp[5]…dp[1](正序结果一样)

  7. 一共有两种情况,假设dp[3](抢劫金额为3)

    • 如果不选银行3,那么 dp1[3] = dp[3]
    • 如果选银行3,那么 dp2[3] = (1-0.05)*dp[6-3]
    • 总结:dp[3] = max( dp1[3],dp2[3] )
  8. 得到转移方程:

    dp[j] = max((1-a[i].p)*dp[j-a[i].money],dp[j]);

  9. P(被抓) = 1-0.04=0.96

  10. 倒序依此循环dp,出现第一个 >= 0.96的为最优解

模拟

Bank=1

dp[6] = max( (1 - 0.02) * dp[ 6-1 ] , dp[6] ) = 0
dp[5] = max( (1 - 0.02) * dp[ 5-1 ] , dp[5] ) = 0
dp[4] = max( (1 - 0.02) * dp[ 4-1 ] , dp[4] ) = 0
dp[3] = max( (1 - 0.02) * dp[ 3-1 ] , dp[3] ) = 0
dp[2] = max( (1 - 0.02) * dp[ 2-1 ] , dp[2] ) = 0
dp[1] = max( (1 - 0.02) * dp[ 1-1 ] , dp[1] ) = max( 0.98 * 1 , 0 ) = 0.98

Bank=2

dp[6] = max( (1 - 0.03) * dp[ 6-2 ] , dp[6] ) = 0
dp[5] = max( (1 - 0.03) * dp[ 5-2 ] , dp[5] ) = 0
dp[4] = max( (1 - 0.03) * dp[ 4-2 ] , dp[4] ) = 0
dp[3] = max( (1 - 0.03) * dp[ 3-2 ] , dp[3] ) = max( 0.97 * 0.98 , 0 ) = 0.9506
dp[2] = max( (1 - 0.03) * dp[ 2-2 ] , dp[2] ) = max( 0.97 * 1 , 0 ) = 0.97

Bank=3

dp[6] = max( (1 - 0.05) * dp[ 6-3 ] , dp[6] ) = max( 0.95 * 0.9506 , 0 ) = 0.90307
dp[5] = max( (1 - 0.05) * dp[ 5-3 ] , dp[5] ) = max( 0.95 * 0.97 , 0 ) = 0.9215
dp[4] = max( (1 - 0.05) * dp[ 4-3 ] , dp[4] ) = max( 0.95 * 0.98 , 0 ) = 0.931
dp[3] = max( (1 - 0.05) * dp[ 3-3 ] , dp[3] ) = max( 0.95 * 1 , 0.9506 ) = 0.9506

dp[]={ 1, 0.97, 0.9506, 0.931, 0.9215, 0.90307 }
1 - 0.04 = 0.96
0.97 > 0.96 > 0.931
高于0.96的第一个数就是0.97.对应的是 抢劫金额总量为2
即答案为2

完整代码

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

struct node
{
	int money;
	double p;
}Node;

double dp[10005];
int main()
{
	int N;
	cin>>N;
	while(N--)
	{
		double pBu;
		int nBank;
		cin>>pBu>>nBank;
		node a[100];
		int total=0;
		for(int i=0;i<nBank;i++)
		{
			cin>>a[i].money>>a[i].p;
			total +=a[i].money; 
		}
		memset(dp,0,sizeof(dp));
		dp[0]=1;
		for(int i=0;i<nBank;i++)
		{
			for(int j=total;j>=a[i].money;j--)
			{
				dp[j] = max((1-a[i].p)*dp[j-a[i].money],dp[j]);
			}
		}
		for(int i=total;i>=0;i--)
		{
			if(dp[i] >= 1-pBu)
			{
				cout<<i<<endl;
				break;
			}
		}

	}
}

猜你喜欢

转载自blog.csdn.net/DanBo_C/article/details/89889660
今日推荐