题意:求和不大于m值的硬币组合数。
分析:
多重背包的可行性问题。
可以根据《背包九讲》的多重背包模板稍加修改
procedureMultiplePack(cost,weight,amount)
if cost*amount>=V
CompletePack(cost,weight)
return
integer k=1
while k<amount
ZeroOnePack(k*cost,k*weight)
amount=amount-k
k=k*2
ZeroOnePack(amount*cost,amount*weight)
这里由于只需要判断可行性,不需找最优解,故直接写
for(j=cost,j<=m;j++)
f[j]=f[j]||f[j-a[i]];即可。
f要开成bool型不然再poj 上会超时。。。
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int a[100005],c[100005];
bool f[100005];
int main()
{
int n,m,tmp,ans,t;
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==0 && m==0)
break;
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
for(int i=0;i<n;i++)
scanf("%d",&c[i]);
memset(f,0,sizeof(f));
f[0]=1;
for(int i=0;i<n;i++)
{
if(a[i]*c[i]>=m) //完全背包
{
for(int j=a[i];j<=m;j++)
f[j]=f[j]||f[j-a[i]];
}
else //01背包
{
tmp=1;
t=c[i];
while(tmp<t)
{
for(int j=m;j>=tmp*a[i];j--)
f[j]=f[j]||f[j-tmp*a[i]];
t-=tmp;
tmp=tmp<<1;
}
if(t)
{
for(int j=m;j>=t*a[i];j--)
f[j]=f[j]||f[j-t*a[i]];
}
}
}
ans=0;
for(int i=1;i<=m;i++)
if(f[i]) ans++;
printf("%d\n",ans);
}
return 0;
}
还有一种写法= =我理解的不太深入。。。。。
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int a[100005],c[100005],u[100005];
bool f[100005];
int main()
{
int n,m,ans;
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==0 && m==0)
break;
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
for(int i=0;i<n;i++)
scanf("%d",&c[i]);
memset(f,0,sizeof(f));
ans=0,f[0]=1;
for(int i=0;i<n;i++)
{
memset(u,0,sizeof(u));
for(int j=a[i];j<=m;j++)
{
if(!f[j] && f[j-a[i]] && u[j-a[i]]+1<=c[i])
{
f[j]=1;
u[j]=u[j-a[i]]+1;
ans++;
}
}
}
printf("%d\n",ans);
}
return 0;
}
//HDU 2844 && POJ 1742
参考了:
http://blog.csdn.net/ice_crazy/article/details/8668896
很感谢,又进一步理解了背包九讲的细节。。。