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 }