[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;
}

 

     

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页