AHU-743 多重部分和问题 【多重背包变种】

Description
有n种不同大小的数字,每种各个。判断是否可以从这些数字之中选出若干使它们的和恰好为K。
 
Input
首先是一个正整数T(1<=T<=100)
接下来是T组数据
每组数据第一行是一个正整数n(1<=n<=100),表示有n种不同大小的数字
第二行是n个不同大小的正整数ai(1<=ai<=100000)
第三行是n个正整数mi(1<=mi<=100000),表示每种数字有mi个
第四行是一个正整数K(1<=K<=100000)

 

Output
对于每组数据,如果能从这些数字中选出若干使它们的和恰好为K,则输出“Yes”,否则输出“No”,每个输出单独占一行

 

Sample Input
2
3
3 5 8
3 2 2
17
2
1 2
1 1
4
 
Sample Output
Yes
No



题解:

15年省赛的一道题,题目没啥难度,看下数据范围多重背包可以跑,只需要看某个状态i是否可以达到用bool数组就行,二进制优化0ms。


代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define INF 0x3f3f3f3f
 4 #define M(a, b) memset(a, b, sizeof(a))
 5 const int N = 105;
 6 int a[N], num[N];
 7 bool f[100005];
 8 
 9 int main() {
10     int T, n, k;
11     scanf("%d", &T);
12     while (T--) {
13         scanf("%d", &n);
14         for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
15         for (int i = 1; i <= n; ++i) scanf("%d", &num[i]);
16         scanf("%d", &k);
17         M(f, 0); f[0] = 1;
18         for (int i = 1; i <= n; ++i) {
19             int sum = num[i] * a[i];
20             if (sum >= k) {
21                 for (int j = a[i]; j <= k; ++j)
22                     if (f[j-a[i]]) f[j] = 1;
23             }
24             else {
25                 int m = num[i];
26                 for (int j = 1; j <= m; m-=j, j <<= 1) {
27                     int y = j*a[i];
28                     for (int x = k; x >= y; --x)
29                         if (f[x-y]) f[x] = 1;
30                 }
31                 int y = m*a[i];
32                 for (int x = k; x >= y; --x)
33                     if (f[x-y]) f[x] = 1;
34             }
35         }
36         if (f[k]) printf("Yes\n");
37         else printf("No\n"); 
38     }
39 
40     return 0;
41 }

 

posted @ 2017-05-02 13:41 Robin! 阅读(...) 评论(...) 编辑 收藏