POJ 3260The Fewest Coins 多重背包+完全背包+鸽巢原理

这篇博客介绍了POJ 3260问题,涉及多重背包和完全背包策略。John有限的硬币需购买价值T的商品,店主硬币无限。通过证明,确定背包上限为max_v*max_v+T(max_v为最大硬币价值)。当支付超过max_v*max_v+T时,找不到最优解。文中提供了AC代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

POJ 3260 题目链接

poj3260

一、题目大意

John去买东西,他有n种不同面值的硬币(i∈[1,n]),每种硬币的价值对应Vi ,每种硬币的数量对应Ci, John想要买一共价值T的商品;
店主有和John同样多总类的硬币,但是每种硬币的数量都无限多;
John花费硬币的价值与店主找零的硬币的价值之差为T;
:John花费硬币的数量与店主花费硬币的数量之和最小值是多少,不存在则输出 -1

二、问题分析

dp[i]:在硬币价值为i的情况下,John所花费的最小硬币数,初始化为INF;
dp1[i]:在硬币价值为i的情况下,店主所花费的最小硬币数,初始化为INF;
John的硬币数量有限所以dp[i]计算的是多重背包(我用了双端队列去优化dp,但是O(nlogn)的那种方法也不会超时);
店主的硬币数量无限所以dp1[i]计算的是完全背包;
最重要的就是背包上限的确立:此题的背包上限为max_v*max_v+T(max_v为最大硬币价值);

证明

鸽巢定理

根据上图定理:
首先 ,max_v个数相加肯定会有一个子序列的和为max_v 的倍数,及sub1=b * max_v+r,sub2=c * max_v+r,则sub2-sub1得到的子序列和为max_v的倍数;
假设,顾客支付了超过max_v*max_v+T的钱时,店长需要找价值超过为max_v*max_v的硬币,此时店主找的硬币数大于max_v,价值Vi<=max_v,根据上述定理硬币序列中会存在两个子序列sub1,sub2其差值为n*max_v,如果子序列不完全由max_v组成,那么可以用max_v替换,因此子序列肯定可以被替换;
所以店主要找的钱超过max_v*max_v后,其找钱的序列中肯定存在n*max_v的子序列(被替换后)(n>1),而此时只要顾客少支付max_v的硬币,店主也可以少找零max_v的硬币,说以max_v*max_v后不存在最优解!

参考解析https://www.hankcs.com/program/algorithm/poj-3260-the-fewest-coins.html

三、AC代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define INF 0x3f3f3f3f
const int N=25020;

int v[N],c[N],quev[N],que[N],dp[N],dp1[N];

int
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值