题目:POJ1742.
题目大意:给定
n
n
n种物品,物品
i
i
i价值为
A
i
A_i
Ai,数量为
C
i
C_i
Ci,问
1
m
1~m
1 m之间多少种面值能被凑出来.
1
≤
n
≤
100
,
1
≤
m
,
A
i
≤
1
0
5
,
1
≤
C
i
≤
1
0
3
1\leq n\leq 100,1\leq m,A_i\leq 10^5,1\leq C_i\leq 10^3
1≤n≤100,1≤m,Ai≤105,1≤Ci≤103.
一道多重背包的模板,当然可以用二进制拆分或者单调队列优化做,但是感觉这样做很麻烦.
考虑这个问题的特殊性,发现它只是要求可行性,我们是否可以从这里入手优化呢?
若当前正在枚举第 i i i种物品, f [ j ] f[j] f[j]表示价值 j j j是否能够被拼凑出来,容易发现前面 i − 1 i-1 i−1种物品造成的影响已经没用了,我们只需要考虑当前第 i i i种物品造成的影响即可.
贪心的想,容易发现如果 j j j的价值可以只通过 k k k枚第 i i i种物品凑出来,我们肯定不考虑比 k k k枚更多的硬币,所以考虑记录一下使 f [ j ] = 1 f[j]=1 f[j]=1最少需要物品 i i i的数量 u s e [ j ] use[j] use[j].每次枚举到第 i i i种物品的时候先把 u s e use use数组初始化为 0 0 0,转移的时候若发现 f [ j ] = 1 f[j]=1 f[j]=1或 f [ j − a [ i ] ] = 0 f[j-a[i]]=0 f[j−a[i]]=0或 u s e [ j − a [ i ] ] > = c [ i ] use[j-a[i]]>=c[i] use[j−a[i]]>=c[i]时就不管了,否则就让 f [ j ] = 1 , u s e [ j ] = u s e [ j − a [ i ] ] + 1 f[j]=1,use[j]=use[j-a[i]]+1 f[j]=1,use[j]=use[j−a[i]]+1.
时间复杂度 O ( n m ) O(nm) O(nm).
代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=100,M=100000;
int n,m,a[N+9],c[N+9];
int dp[M+9],use[M+9],ans;
Abigail into(){
for (int i=1;i<=n;++i)
scanf("%d",&a[i]);
for (int i=1;i<=n;++i)
scanf("%d",&c[i]);
}
Abigail work(){
for (int i=1;i<=m;++i) dp[i]=0;
dp[0]=1;
for (int i=1;i<=n;++i){
for (int j=0;j<=m;++j) use[j]=0;
for (int j=a[i];j<=m;++j)
if (!dp[j]&&dp[j-a[i]]&&use[j-a[i]]<c[i]) dp[j]=1,use[j]=use[j-a[i]]+1;
}
ans=0;
for (int i=1;i<=m;++i) ans+=dp[i];
}
Abigail outo(){
printf("%d\n",ans);
}
int main(){
while (~scanf("%d%d",&n,&m)&&n+m){
into();
work();
outo();
}
return 0;
}