01背包 + 概率 之 hdu 2955

//  [7/20/2014 Sjm]
/*
看到此题时,第一个想法是:
以P作为体积,Pj作为费用,Mj作为价值。
但是,double类型的不能作为数组下标,于是此法行不通。
 
于是,从另一角度考虑:
被抓的概率不能超过上限,即不被抓的概率要大于下限(下限 = 1 - 被抓概率的上限)。
以总的银行金额作为体积,每一个银行金额作为费用,不被抓的概率作为价值。
即 dp[i][j] := 抢劫了前 i 个银行,所获金额至多为 j 的最大不被抓的概率。
另外只有当每一个银行都没抓到 Roy 才可以。所以求概率时,要相乘。
由此可求出答案。
********注意********
初始化时,dp[0] = 1,若不抢劫银行,则不被抓的概率为 1。
*/
 1 #include <iostream>
 2 #include <cstdlib>
 3 #include <cstdio>
 4 #include <algorithm>
 5 using namespace std;
 6 const int MAX = 105;
 7 const int MAX_mil = 10005;
 8 
 9 struct node {
10     int millions;
11     double prb;
12 };
13 
14 node arr[MAX];
15 int sum;
16 double P;
17 int N;
18 double dp[MAX_mil];
19 
20 int Solve()
21 {
22     fill(dp, dp + sum + 1, 0);
23     dp[0] = 1;
24     for (int i = 1; i <= N; ++i) {
25         for (int j = sum; j >= arr[i].millions; --j) {
26             dp[j] = max(dp[j], dp[j - arr[i].millions] * arr[i].prb);
27         }
28     }
29     for (int j = sum; j >= 0; --j) {
30         if (dp[j] > P) {
31             return j;
32         }
33     }
34     return 0;
35 }
36 
37 int main()
38 {
39     //freopen("input.txt", "r", stdin);
40     int T;
41     scanf("%d", &T);
42     while (T--) {
43         sum = 0;
44         scanf("%lf %d", &P, &N);
45         P = 1 - P;
46         for (int i = 1; i <= N; ++i) {
47             scanf("%d %lf", &arr[i].millions, &arr[i].prb);
48             arr[i].prb = 1 - arr[i].prb;
49             sum += arr[i].millions;
50         }
51         printf("%d\n", Solve());
52     }
53     return 0;
54 }

 

posted @ 2014-07-20 17:17  JmingS  阅读(156)  评论(0编辑  收藏  举报