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 }