题目链接: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\n");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\n");
else printf("%d\n",ans);
return 0;
}