给定N种硬币,其中第 i 种硬币的面值为Ai,共有Ci
个。
从中选出若干个硬币,把面值相加,若结果为S,则称“面值S能被拼成”。
求1~M之间能被拼成的面值有多少个。
输入格式
输入包含多组测试用例。
每组测试用例第一行包含两个整数N和M。
第二行包含2N个整数,分别表示A1,A2,…,AN
和C1,C2,…,CN
。
当输入用例N=0,M=0时,表示输入终止,且该用例无需处理。
输出格式
每组用例输出一个结果,每个结果占一行
我们可以考虑每种硬币是否被应用于拼成最后的面值,在i阶段时,f[j]表示在前i种硬币能否拼成面值为j。
我们可以发现前i种能拼成j只有两类情况。
1:前i-1种硬币就能拼成面值为j,然后在第i阶段开始时,f[j]已经成为true
2:使用了第i种硬币,即在第i阶段时递推中,发现f[j-v[i]]为true,从而f[j]变为true。
我们那可以建立一个数组used,used[j]表示f[j]在阶段i时为true至少需要多少枚第i种硬币,如果f[j-a[i]]为true时,f[j]已经为true,然后就不进行转移。并且used[j]=0;否则f[j]=f[j]或者f[j-a[[i]]的转移
#include<iostream>
#include<cstring>
using namespace std;
const int N=110,M=100010;
int v[N],s[N];
int f[M],used[M];
int n,m;
int main()
{
while(scanf("%d %d",&n,&m),n||m){
for(int i=1;i<=n;i++)
scanf("%d",&v[i]);
for(int i=1;i<=n;i++)
scanf("%d",&s[i]);
memset(f,0,sizeof(f));
f[0]=1;
for(int i=1;i<=n;i++)
{memset(used,0,sizeof (used));
for(int j=v[i];j<=m;j++)
{
if(!f[j]&&f[j-v[i]]&&used[j-v[i]]<s[i])
{
f[j]=1;
used[j]=used[j-v[i]]+1;
}
}
}
int res=0;
for(int i=1;i<=m;i++)
res+=f[i];
cout<<res<<endl;;
}
return 0;
}