LightOJ1079 Just another Robbery 01背包、概率

题意:给出银行的个数和被抓概率上限P。在给出每个银行的钱和抢劫这个银行被抓的概率不超过被抓概率上线能抢劫到最多的钱

两种方法

方法一:dp[j]为抢劫了j元钱不被抓到概率,状态转移方程dp[j] = max(dp[j], dp[j - w[i]] * p[i])

#include <iostream>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;

const int maxn = 10010;
double dp[maxn];
double p[maxn];
int w[maxn];

int main()
{
    //freopen("in.txt", "r", stdin);
    int T;
    int cas = 0;
    scanf("%d", &T);
    while(T--)
    {
        int sum = 0;
        double P;
        int n;
        scanf("%lf%d", &P, &n);
        for(int i = 1; i <= n; i++)
        {
            scanf("%d%lf", &w[i], &p[i]);
            p[i] = 1.0-p[i];
            sum += w[i];
        }
        for (int i = 0; i <= sum; i++)
        {
            dp[i] = 0;
        }
        dp[0] = 1.0;  //没有枪钱那么不被抓的概率就是1
        for(int i = 1; i <= n; i++)
        {
            for(int j = sum; j >= w[i]; j--)
            {
                if (dp[j - w[i]]) {  //当dp[j - w[i]>0才有比较的必要,不然dp[j - w[i]] * p[i]=0,这样做更加省时。
                    dp[j] = max(dp[j], dp[j - w[i]] * p[i]);  
                }
            }
        }
        for(int i = sum; i >= 0; i--)
        {
            if(1-dp[i] <= P)
            {
                printf("Case %d: %d\n", ++cas, i);
                break;
            }
        }
    }
    return 0;
}

方法二:
dp[i][j]表示前 i 个银行抢劫到 j 这么多钱被抓的概率。
转移方程 dp[i][j] = min(dp[i-1][j] , dp[i-1][j-v[i]])
#include<cstdio>
#include<algorithm>
using namespace std;
double d[111][11100];
int main(){
    int t,n,x[111];
    double p,y[111];
    scanf("%d",&t);
    for(int cse=1; cse<=t; ++cse){
        scanf("%lf%d",&p,&n);
        int sum=0;
        for(int i=1; i<=n; ++i){
            scanf("%d%lf",x+i,y+i);
            sum+=x[i];
        }
        for(int i=0; i<=n; ++i){
            for(int j=0; j<=sum; ++j) d[i][j]=1;
        }
        d[0][0]=0;
        for(int i=1; i<=n; ++i){
            for(int j=0; j<=sum; ++j){
                if(j>=x[i]) d[i][j]=min(d[i-1][j],d[i-1][j-x[i]]+(1-d[i-1][j-x[i]])*y[i]);
                else d[i][j]=d[i-1][j];
            }
        }
        for(int i=sum; i>=0; --i){
            if(d[n][i]<p){
                printf("Case %d: %d\n",cse,i);
                break;
            }
        }
    }
    return 0;
}




猜你喜欢

转载自blog.csdn.net/qihang_qihang/article/details/78658376