题目分析 给定N和M,N表示硬币的种类,M表示最大不超过的总价值,
相当于背包的重量或体积等一类的限制条件。A[1....N]表示硬币的面值
C[1....N]表示相应的硬币的数目。
求能用这些硬币组合成多少种金额(金额在1~M之间)?
转换为背包问题就是1~M中间的数值能否可以被组成。通常所做的背包是
求最大值是那种金额?这里我们如果可以到某一个值i那么令dp[i]=1表示可以取到。
#include<stdio.h>
int M,dp[100001];
//O1背包
void ZeroOnePack(int c,int w)
{
for(int i=M;i>=c;i--)
dp[i]=dp[i]|dp[i-c];
}
//完全背包
void CompletePack(int c,int w)
{
for(int i=c;i<=M;i++)
dp[i]=dp[i]|dp[i-c];
}
//多重背包
void MultiplePack(int c,int w,int n)
{
if(c*n>=M)
{
CompletePack(c,w);
return;
}
int k=1;
while (k<=n)
{
ZeroOnePack(k*c,k*w);
n-=k;
k*=2;
}
ZeroOnePack(n*c,n*w);
}
int main()
{
int N,a[101],c[101];
while (scanf("%d%d",&N,&M)!=EOF)
{
if(!N&&!M) break;
for(int i=1;i<=N;i++)
scanf("%d",&a[i]);
for(int i=1;i<=N;i++)
scanf("%d",&c[i]);
//初始化需要注意,dp[0]表示一种方案满足金额为0 dp[1...M]初始化为没有方案满足
//这里的dp[i]表示根据是否又满足金额为i 是为1 否为0
for(int i=0;i<=M;i++)
dp[i]=0;
dp[0]=1;
for(int i=1;i<=N;i++)
MultiplePack(a[i],a[i],c[i]);
int sum=0;
for(int i=1;i<=M;i++)
sum+=dp[i];
printf("%d
",sum);
}
return 0;
}