题目意思:
要求你再给出的M范围(1~M),分别用给出的钱币,以及所对应的数量。求出看能并凑出的钱数有多少在(1~M)之间,包括边界。。
此题一看就应该可以猜到是用DP做,还有就是可以想到利用母函数。但是再看看数据,就可以排除一般DP,还有就是母函数的M值太大,可能会超时,因此这也是不可行的。
因此就看看DP可以完成了吗!!但是若直接DP可能也会数据就太大,因此也就要分开考虑。—:当一组数据的乘积大于M是,和当小于时,这里就分开考虑.
当数据积大于时,你就可以用完全背包(可以无限利用)直到不符合条件。二:就是小于时,当前的价值是加还是不加都有可能产生不同的结果。因此就可以利用01背包(加或者不加)的方法解决。
接着就是看代码:(细看代码)
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstdlib>
using namespace std;
const int maxn=100005;
int a[105],c[105];
int dp[maxn];
int n,m;
void compty(int x)//完全背包。
{
int i;
for(i=x;i<=m;i++)
dp[i]=max(dp[i],dp[i-x]);
}
void beibao_01(int x)//01背包。可以看着次数。
{
int i;
for(i=m;i>=x;i--)
{
dp[i]=max(dp[i],dp[i-x]);
}
}
void shuju(int cons,int n)
{
int k;
if(cons*n>m)//当输入的数据大于总的M时,应该考虑可以加入的次数,就是(转换妫完全背包题),完全背包,可以去好多次,直到不满足条件为止!
compty(cons);
else
{
k=1;
while(k<n)//当然在小于时就必须考虑这依次是否家还是不加,这就考虑的是01背包的问题。
{
beibao_01(cons*k);
n-=k;
k++;
}
beibao_01(cons*n);
}
}
int main()
{
int i,j;
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==0&&m==0)break;
memset(a,0,sizeof(a));
memset(c,0,sizeof(c));
for(i=1;i<=n;i++)scanf("%d",&a[i]);
for(i=1;i<=n;i++)scanf("%d",&c[i]);
memset(dp,0,sizeof(dp));//初始化,
dp[0]=1;
for(i=1;i<=n;i++)
{
shuju(a[i],c[i]);//依次考虑,分别对你每一个数据谈论!!
}
int sum=0;
for(i=1;i<=m;i++)
{
if(dp[i])
sum++;
}
cout<<sum<<endl;
}
return 0;
}