poj3260[USACO2006,Dec]The Fewest Coins最少找零

题目链接: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;
}


posted @ 2016-10-14 22:23  OxQ  阅读(228)  评论(0编辑  收藏  举报