题目链接:http://poj.org/problem?id=3260
题目大意:
题解:
完全背包+多重背包
预处理g[i]表示老板找i块钱时要花的最少纸币数。——完全背包
f[i]表示'我'花i块钱时要用的最少纸币数。——多重背包(这个肯定要用二进制优化啦
最后的答案就是min(f[i],g[t-i])。
主要就是找钱的上限怎么找!一直WA!
orz.看网上的证明其实并不是很懂。。其实想到做法就好了吧。~吧~
#include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> using namespace std; #define maxn 101000 #define inf 1000000000 int c[110],v[110]; int f[maxn],g[maxn]; int mymin(int x,int y){return (x<y)?x:y;} int mymax(int x,int y){return (x>y)?x:y;} int main() { //freopen("fewcoins.in","r",stdin); //freopen("fewcoins.out","w",stdout); int n,t,i,j,k,ans; scanf("%d%d",&n,&t); for (i=1;i<=n;i++) scanf("%d",&v[i]); int sum=0,mx=0; for (i=1;i<=n;i++) { scanf("%d",&c[i]); sum+=c[i]*v[i]; mx=mymax(mx,v[i]*v[i]); }//t+mx当找钱的上限 if (sum<t) {printf("-1 ");return 0;} memset(g,63,sizeof(g)); memset(f,63,sizeof(f)); g[0]=0;f[0]=0; for (i=1;i<=n;i++) for (j=v[i];j<=t+mx;j++) g[j]=mymin(g[j],g[j-v[i]]+1); for (i=1;i<=n;i++) { for (j=1;j<=c[i];j*=2) { for (k=t+mx;k>=j*v[i];k--) f[k]=mymin(f[k],f[k-j*v[i]]+j); c[i]-=j; } if (c[i]!=0) for (k=t+mx;k>=c[i]*v[i];k--) f[k]=mymin(f[k],f[k-c[i]*v[i]]+c[i]); }ans=inf; for (i=t;i<=t+mx;i++) ans=mymin(f[i]+g[i-t],ans); if (ans==inf) printf("-1 "); else printf("%d ",ans); return 0; }