您的位置:首页 > Web前端

POJ3260 The Fewest Coins 多重背包+完全背包

2013-08-29 10:33 423 查看
题意:说有一个人去买m元的东西,有n种钱币,没种钱币的面额是w[i],个数是C[i],售货员每种钱币有无数多个。现在这个人想让交易的钱个数最少,即找回的和付出钱的张数,最少。

多重背包+完全背包。

买家:多重背包;售货员:完全背包;

开两个数组,分别计算出买家,售货员每个面额的最少张数。

 

最重要的是上界的处理。可以注意到,上界为maxw*maxw+m(maxw最大面额的纸币),也就是24400元。(网上的证明)证明如下:

如果买家的付款数大于了maxw*maxw+m,即付硬币的数目大于了maxw,根据鸽笼原理,至少有两个的和对maxw取模的值相等,也就是说,这部分硬币能够用更少的maxw来代替。证毕。

真心不懂证明也没关系,记住结论就好了,真心不想记结论也没关系,数组开大一点就好了。

AC代码:




View Code

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define INF 1<<29
int m, n;
int w[101],c[101];
int dp[24563],f[24563]; //dp[]买家,f[]售货员,注意上界证明
int main()
{
int i, j, maxn;
while(~scanf("%d%d",&n,&m))
{
maxn=0;
for(i=1;i<=n;i++)
scanf("%d",&w[i]),maxn=max(maxn,w[i]);
for(i=1;i<=n;i++)
scanf("%d",&c[i]);
maxn=maxn*maxn+m+1;
//多重背包
fill(dp,dp+maxn+1,INF); //把dp[0]~dp[maxn]赋值INF
dp[0]=0;
for(i=1;i<=n;i++)
if(c[i]*w[i]>=maxn)
{
for(j=w[i];j<=maxn;j++)
dp[j]=min(dp[j],dp[j-w[i]]+1);
}
else
{
int k=1;
while(k<c[i])
{
for(j=maxn;j>=w[i]*k;j--)
dp[j]=min(dp[j],dp[j-w[i]*k]+k);
c[i]-=k;
k*=2;
}
for(j=maxn;j>=w[i]*c[i];j--)
dp[j]=min(dp[j],dp[j-w[i]*c[i]]+c[i]);
}
//完全背包
fill(f,f+maxn+1,INF);f[0]=0;
for(i=1;i<=n;i++)
for(j=w[i];j<=maxn;j++)
f[j]=min(f[j],f[j-w[i]]+1);
//统计最小值
int ans=INF;
for(i=0;i<=maxn-m;i++)
ans=min(ans,dp[i+m]+f[i]);
if(ans==INF)ans=-1; //不能找出,调整输出为-1.
printf("%d\n",ans);
}
return 0;
}


 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: