HDU 2955 01背包

来源:互联网 发布:js在线格式化 编辑:程序博客网 时间:2024/04/29 23:06

题目点我
题目大意:给了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 105double 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;}
0 0
原创粉丝点击