背包解组合数学问题,n种物品,每种num[i]个,求取r个的方法数。
背包思想,f[j]表示当前取j个数的方法数,则状态转移方程为
f[j] += f[k](max(j - num[i], 0) <= k < j)
外层循环枚举物品,内层循环从大到小枚举空间,最内层枚举方法数。
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
using namespace std;
typedef long long LL;
const int N = 1000;
int num[N], que[N], n, m;
LL f[N];
int main(){
freopen("1285.txt", "r", stdin);
int cas = 0;
while(~scanf("%d %d", &n, &m ) && n){
memset(num, 0, sizeof(num));
int tp;
for(int i = 0; i < n ;i++){
scanf("%d", &tp);
tp--;
num[tp]++;
}
for(int i = 0; i < m; i++){
scanf("%d", &que[i]);
}
memset(f, 0, sizeof(f));
for(int i = 0 ;i <= num[0]; i++){
f[i] = 1;
}
for(int i = 1; i < n; i++){
for(int j = n; j >= 1; j--){
for(int k = max(j - num[i], 0); k < j ; k ++){
f[j] += f[k];
}
}
}
cas++;
printf("Case %d:\n", cas);
for(int i = 0; i < m; i++){
printf("%I64d\n", f[que[i]]);
}
}
return 0;
}