# HDU4815 Little Tiger vs. Deep Monkey——0-1背包

## 样例输入

1
3 0.5
1 2 3

## 样例输出

3

## 错误示例

 1 #include<iostream>
2 #include<stdio.h>
3 #include<string.h>
4 #include<math.h>
5 using namespace std;
6
7 int k[45];
8 int a[40005];
9 int b[40005];
10 int n;
11 double p;
12
13 void dfs(int i, int flag, int sum){            //第i个 选or不选 前一个状态的和
14     if(i > n){            //只有当所有的n个都作出了选择之后才能算是一种选择方案
15         a[sum]++;
16         return;
17     }
18     if(flag == 1){            //选
19         int next_sum = sum + k[i];
20 //        a[next_sum]++;
21         dfs(i+1, 1, next_sum);
22         dfs(i+1, 0, next_sum);
23     }else{                    //不选
24         int next_sum = sum;
25 //        a[next_sum]++;
26         dfs(i+1, 1, next_sum);
27         dfs(i+1, 0, next_sum);
28     }
29 }
30
31 void run(){
32     //下一个的下标 选or不选 目前为止的和
33     dfs(1, 1, 0);
34     dfs(1, 0, 0);
35 }
36
37 void pre(){
38     b[1] = 1;
39     int end = n*1000;
40     for(int i = 2; i <= end; i++){    //b[i]存放比i小的取法的数量
41         b[i] = b[i-1] + a[i-1];
42     }
43 }
44
45 void judge(){
46     double m = 1;
47     for(int i = 1; i <= n; i++){
48         m *= 2;
49     }
50     m *= p;
51     long long x = ceil(m);
52     int ans;
53     int end = n*1000;
54     for(int i = 1; i <= end; i++){
55         if(b[i] >= x){
56             ans = i;
57             break;
58         }
59     }
60     printf("%d\n", ans);
61 }
62
63 int main(){
64     int t;
65     scanf("%d", &t);
66     while(t--){
67         scanf("%d%lf", &n, &p);
68         memset(a, 0, sizeof(a));
69         memset(b, 0, sizeof(b));
70         for(int i = 1; i <= n; i++) scanf("%d", &k[i]);
71         run();
72         pre();
73         judge();
74     }
75     return 0;
76 } 

## 正确代码

 1 #include<iostream>
2 #include<stdio.h>
3 #include<math.h>
4 #include<string.h>
5 using namespace std;
6
7 const int N = 40005;
8 int a[45];
9 double dp[N];
10 int n;
11 double p;
12
13 int main(){
14     int t;
15     scanf("%d", &t);
16     while(t--){
17         scanf("%d%lf", &n, &p);
18         int sum = 0;
19         for(int i = 1;i <= n; i++){        //sum统计最大可以得到的分数
20             scanf("%d", &a[i]);
21             sum += a[i];
22         }
23         memset(dp, 0, sizeof(dp));
24         dp[0] = 1;                //前0题，得到0分的次数位1
25         for(int i = 1; i <= n; i++){            //类似于0-1背包的两个循环
26             for(int j = sum; j >= a[i]; j--){
27                 dp[j] += dp[j-a[i]];            //核心步骤，对于dp[j]而言，得分为j的种数是前i-1个时得分为j-a[i] 也就是取第i题,加上前i-1个时得分为j的种数 也就是不取第i题
28             }
29         }
30         double m = pow(2,n);        //统计所有的深猴的得分个数
31         int ans = 0;
32         double ssum = 0;
33         for(int i = 0; i <= sum; i++){
34             dp[i] /= m;                //从小到大将概率累加直到大于等于p时的分数i就是答案，注意0也是一个得分
35             ssum += dp[i];
36             if(ssum >= p){
37                 ans = i;
38                 break;
39             }
40         }
41         printf("%d\n", ans);
42     }
43     return 0;
44 }

posted on 2019-08-18 16:49  乌克兰大野猪  阅读(...)  评论(...编辑  收藏