您的位置:首页 > Web前端

背包问题--POJ 3260 The Fewest Coins【完全背包+多重背包】

2011-02-14 13:44 549 查看
POJ 3260 The Fewest Coins

网上有篇很好的报告,觉得不错,就拷了些过来,(*^__^*) 嘻嘻……

网址:http://www.cppblog.com/Davidlrzh/articles/135614.html

题意:John去买东西,东西的价格是T(1 <= T <= 10000),John所在的地方有n(1 <= n <= 100)种的硬币,面值分别为V1, V2, ..., Vn (1 <= Vi <= 120)。John带了C1枚面值为V1的硬币,C2枚面值为V2的硬币,...,Cn枚面值为Vn的硬币(0 <= Ci <= 10000)。售货员那里每种硬币都有无限多个。问为了支付这个T,John给售货员的硬币数目加上售货员找回的零钱的硬币数目最少是多少。如果无法支付 T,输出-1 。

解法:支付时硬币数量有限制,为多重背包问题,通过二进制方法转化为01背包求解。找零时,硬币数量无限制,为完全背包问题。对两问题分别求解,然后找出差额为T时,两者和的最小值即为所示。

其中:给钱上界为:T+maxValue^2,其中maxValue为最大硬币面值。证明:反证法。假设存在一种支付方案,John给的钱超过 T+maxValue^2, 则售货员找零超过maxValue^2,则找的硬币数目超过maxValue个,将其看作一数列,求前n项和sum(n),根据鸽巢原理,至少有两 个对maxValue求模的值相等,假设为sum(i)和sum(j),i<j,则i+1...j的硬币面值和为 maxValue的倍数,同理,John给的钱中也有 一定数量的硬币面值和为maxValue的倍数,则这两堆硬币可用数量更少的maxValue面值硬币代替,产生更优方案。

分析:1.给钱时,硬币数有限制,为多重背包问题。
2.找钱时,硬币数无限制,为完全背包问题。
3.给钱上界为:T+maxValue^2,其中maxValue为最大硬币面值。证明:反证法。假设存在一种支付方案,John给的钱超过T+maxValue^2,
则售货员找零超过maxValue^2,则找的硬币数目超过maxValue个,将其看作一数列,求前n项和sum(n),根据鸽巢原理,至少有两
个对maxValue求模的值相等,假设为sum(i)和sum(j),i<j,则i+1j的硬币面值和为maxValue的倍数,同理,John给的钱中也有
一定数量的硬币面值和为maxValue的倍数,则这两堆硬币可用数量更少的maxValue面值硬币代替,产生更优方案。

#include<stdio.h>
#include<string.h>
const int T = 14400+1;
const int T2 = T+14400+2;
const int N = 101;
int change[T];//change[i]表示商店找钱i所需的硬币数
int dp[T2];//dp[i]表示用户付钱i所需硬币数
int c
;
int v
;
__int64 upper;
inline int min(int a,int b)
{
if(a==-1)return b;
return a<b?a:b;
}
void init(int n)
{
memset(change,-1,sizeof(change));
int i,j;
int upper = 0;
change[0]=0;
for(i=0;i<n;i++)
{
for(j=v[i];j<T;j++)
{
if(change[j-v[i]]!=-1)
change[j]=min(change[j],change[j-v[i]]+1);
}
}
}

void zeroOnePack(int v,int c)
{
__int64 i;
for(i=upper;i>=v;i--)
{
if(dp[i-v]!=-1)
dp[i]=min(dp[i],dp[i-v]+c);
}
}
int main()
{
int n,t;
while(scanf("%d%d",&n,&t)!=EOF)
{
int i;
for(i=0;i<n;i++)
scanf("%d",&v[i]);
for(i=0;i<n;i++)
scanf("%d",&c[i]);

if(t==0)
{
printf("0\n");
continue;
}
init(n);

memset(dp,-1,sizeof(dp));
dp[0]=0;
upper = 0;
for(i=0;i<n;i++)
{
upper=upper+c[i]*v[i];
if(upper>=T2)upper = T2-1;
int count = 1;
while(count<c[i])
{
zeroOnePack(v[i]*count,count);
c[i]-=count;
count<<=1;

}
zeroOnePack(v[i]*c[i],c[i]);
}

int ans = -1;

for(i=t;i<=upper;i++)
if(dp[i]!=-1&&(i-t)<T&&change[i-t]!=-1)
ans=min(ans,dp[i]+change[i-t]);

printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: