题意:求和不大于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
很感谢,又进一步理解了背包九讲的细节。。。