题意
给定商品种类 n, 以及背包容量 m
每组数据的第二行 前n个是对应物品价值, 后n个是对应物品数量,
问 有多少种可能使得背包容量 等于 1,m 这个 区间的数
这是另一种表述方法,
有n种货币, 已知每种货币的价值和数量, 问这些货币能够恰好构成1~m的几种情况
题解
先记录一个坑点 … 数组开小了, 会超时, 从头到尾找了半天, 真是太弟弟了
多重背包板子题, 给定了物品的数量限制条件, 很自然就会想到多重背包了
再注意一点的是这里题意的问法比较绕, 实际上就是问遍历 1,m 看看 看看 i==dpi] 的个数
感觉这个题题意需要仔细反复读, 难点是理解问的什么
代码
#include <bits/stdc++.h>
using namespace std;
#define sc scanf
#define pf printf
typedef long long ll;
const int maxn = 1e2+100;
const int maxm = 1e5+100;;
int val[maxn], num[maxn],
dp[maxm],
n, m;
void ZeroOnePack ( int val, int wei ) {
for ( int i = m; i >= val; --i )
dp[i] = max ( dp[i], dp[i - val] + wei );
}
void CompletePack ( int val, int wei ) {
for ( int i = val; i <= m; ++i )
dp[i] = max ( dp[i], dp[i - val] + wei );
}
void MultiplePack ( int val[], int wei[], int num[] ) {
for ( int i = 0; i < n; ++i ) {
if ( val[i] * num[i] >= m ) {
CompletePack ( val[i], wei[i] );
}
else {
int k = 1;
while ( k < num[i] ) {
ZeroOnePack ( k * val[i], k * wei[i] );
num[i] -= k;
k <<= 2;
}
ZeroOnePack ( num[i] * val[i], num[i] * wei[i] );
}
}
}
int main ( ) {
while ( ~sc ( "%d %d", &n, &m ) ) {
if ( n == 0 && m == 0 ) break;
for ( int i = 0; i < n; ++i ) sc ( "%d", &val[i] );
for ( int j = 0; j < n; ++j ) sc ( "%d", &num[j] );
memset ( dp, 0, sizeof ( dp ) );
MultiplePack ( val, val, num );
int cnt = 0;
for ( int i = 1; i <= m; ++i )
if ( dp[i] == i )cnt++;
pf ( "%d\n", cnt );
}
return 0;
}
/*
3 10
1 2 4 2 1 1
2 5
1 4 2 1
0 0
*/