[HDU 2955] Robberies [0-1背包问题]

部分内容来自:https://blog.csdn.net/a1097304791/article/details/83586769

题目描述:

       给定一个被抓的概率P,银行的数量N,抢劫每个银行可得的金额m[i],以及抢劫每个银行会被抓概率p[i],每个银行可以选择抢劫也可以选择不抢劫,求访问完所有的银行后可以抢到的最大金额数,并使总的被抓的概率小于P。

 

        本题是类似0-1背包的问题,可以用dp的方法解决。本题的一个关键是选择什么变量作为“容量”。由于题目中的概率精度未知,无法遍历,所以选择抢到的金额数作为“容量”。

        令P'=1-P,表示访问完所有银行后安全逃脱的最小概率。

       若令dp[i][j] 为访问第i个银行后抢到j元并安全逃脱的最大概率,则dp[N][j]就是访问完所有银行后抢到j元并安全逃脱的最大概率。由于dp[N][j]对应的是最安全的策略,若dp[N][j]<P',则没有一个更安全的方法能够抢到j元并逃脱。因此要找到一个最大的j,满足dp[N][j]>=P'

       dp[i][j]的初始值要怎样设置呢?不难看出,没有访问银行,且没有抢任何钱,成功实现的概率是dp[0][0]=1;而没有访问银行,却抢到了钱,成功的概率是0,即dp[0][j]=0 (j>=1)

       接下来就可以进行dp[i][j]的计算

       状态转移方程: dp[i][j]=max(dp[i-1][j],dp[i-1][j-m[i]]*p[i]) (j>=m[i])

      空间优化: dp[j]=max(dp[j],dp[j-m[i]]*p[i]) (j>=m[i])

 

  

#include <bits/stdc++.h>
using namespace std;
const int maxn=105;
const double eps=1e-9;
int m[maxn];
double p[maxn];
double dp[maxn*maxn];
int sum;
int main()
{
    #ifdef LOCAL_PC
	freopen("E:/1.txt", "r", stdin);
    #endif // LOCAL_PC
    int T;
    cin >> T;
    while(T--)
    {
        double P;
        int N;
        sum=0;
        cin >> P >> N;
        P=1-P;
        for(int i=1;i<=N;++i)
        {
            cin >> m[i] >> p[i];
            p[i]=1-p[i];
            sum+=m[i];
        }

        for(int i=1;i<=sum;++i) dp[i]=0;
        dp[0]=1;

        for(int i=1;i<=N;++i)
        {
            for(int j=sum;j>=m[i];--j)
            {
                dp[j]=max(dp[j],dp[j-m[i]]*p[i]);
            }
        }

        for(int i=sum;i>=0;--i)
        {
            if(dp[i]-P>=eps)
            {
                cout << i << endl;
                break;
            }
        }



    }



	return 0;
}

 

     

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值