HDU 2955 01揹包

題目點我
題目大意:給了N 個銀行的錢Mi 和被抓的概率Pi ,以及一個可以接受的被抓概率P ,要求選擇一些銀行,使得最終被抓概率低於P 的同時,總收益最大。
思路:01揹包問題,一開始想把概率取對數做揹包容量,發現行不通。要用收益當揹包容量,用安全概率當作揹包價值。狀態轉移方程如下:
dp[i][M]=max(dp[i1][M],dp[i1][MMi](1Pi))
其中dp[i][M] 表示,在前i 個銀行中選擇一些,收益爲M 時最大的安全概率。最後按揹包容量M 從高到低遍歷,找到第一個高於1Pdp 值,此時的M 爲安全的最大收益。

這道題的揹包要恰好裝滿,所以開始要把dp[0] 以外的值都初始化爲負數。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define INF -1
#define MAX 10010
#define NUM 105

double dp[MAX];

double max(double a, double b){
    return a > b ? a : b;
}

void ZeroOnePack(double *f, int cost, double p, int vol){
    for(int i = vol; i >= cost; i--)
        f[i] = max(f[i], f[i - cost] * (1 - p));
}

int main(){
    int T, N, i, M[NUM], MaxM = 0;
    double P[NUM], Psafe;
    scanf("%d", &T);
    while(T--){     
        scanf("%lf %d", &Psafe, &N);
        for(i = 0; i < N; i++){
            scanf("%d %lf", &M[i], &P[i]);
            MaxM = MaxM > M[i] ? MaxM : M[i];
        }
        for(i = 1; i < N * MaxM; i++)
            dp[i] = INF;
        dp[0] = 1; //沒搶錢的安全概率 = 1
        for(i = 0; i < N; i++)
            ZeroOnePack(dp, M[i], P[i], N * MaxM);
        for(i = N * MaxM; i >= 0; i--){
            if(dp[i] >= (1 - Psafe)){
                printf("%d\n", i);
                break;
            }
        }
        memset(dp, 0, sizeof(double)*MAX);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章