POJ 3260 The Fewest Coins(多重背包+全然背包)

http://poj.org/problem?id=3260

题意:

John要去买价值为m的商品. 如今的货币系统有n种货币,相应面值为val[1],val[2]…val[n]. 然后他身上每种货币有num[i]个. John必须付给售货员>=m的金钱, 然后售货员会用最少的货币数量找钱给John.

问你John的交易过程中, 他给售货员的货币数目+售货员找钱给他的货币数目 的和最小值是多少?

分析:

本题与POJ 1252类型:

http://blog.csdn.net/u013480600/article/details/40454963

如果John付款总额为S时的货币数目为T1, 售货员找钱 (S-m) 的货币数目为T2. 我们要使得T1+T2最小, 那么自然T1和T2也必须分别是最小的(即T1是当John付款正好S时,最少须要多少张货币.
T2是当售货员正好找钱S-m时,最少须要多少张货币.).

John给的钱肯定>=m, 可是究竟最大多大呢? 假设我们直接求John的全部金钱总和, 然后再DP, 肯定超时. 这个up_bound (即john最多给售货员的钱数) 能够简单设置一个大数值就可以. 网上有个证明(这个证明我也有点不明确):

John的付款数最多为maxv*maxv+m

证明例如以下:

假设John的付款数大于了maxv*maxv+m,即付硬币的数目大于了maxv,依据鸽笼原理。至少有两个的和对maxv取模的值相等(这个意思应该是:至少maxv+1个硬币对maxv求余,然后余数属于[0,maxv-1]范围,肯定有至少两个硬币的余数同样的),也就是说。这部分硬币可以用更少的maxv来取代(这句话我不理解)。

证毕。

第一个问题是一个多重背包问题.

令dp[i][j]==x 表示当John用前i种货币组成j元钱时, 最少须要x张货币.

初始化: dp全为INF(无穷大), 且dp[0][0]=0.

对于每种货币, 我们分情况对它进行处理:

1.    假设val[i]*num[i]>=up_bound时, 做一次全然背包.

2.    假设val[i]*num[i]<up_bound时, 做多次01背包.

终于所求: dp[n][i] 当中i属于[m, up_bound].

第2个问题是一个全然背包问题.

令dp2[i][j]==x 表示售货员用前i种硬币组成j元钱时, 最少须要x张货币.

初始化: dp2全为INF(无穷大), 且dp2[0][0]=0.

状态转移: dp2[i][j] = max( dp2[i-1][j] , dp2[i][j-val[i]]+1 )

终于所求: dp2[n][i] 当中i属于[m, up_bound].

终于合并问题1和问题2的解, 我们枚举i从m到up_bound, 找出dp[i]+dp2[i-m]的最小值就可以.

AC代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define INF 1e9

int n;//n种硬币
int m;//购买商品的价值
int up_bound;//DP价值上界
int val[100+5];//每种硬币价值
int num[100+5];//每种硬币数目
int dp[55555]; //多重背包
int dp2[55555];//全然背包

//1次01背包
void ZERO_ONE_PACK(int *dp,int cost,int sum)
{
    for(int i=up_bound;i>=cost;i--)
        dp[i] = min(dp[i], dp[i-cost]+sum);//注意这里是+sum
}

//1次全然背包
void COMPLETE_PACK(int *dp,int cost)
{
    for(int i=cost;i<=up_bound;i++)
        dp[i] = min(dp[i], dp[i-cost]+1);
}

//1次多重背包
void MULTIPLY_PACK(int *dp,int cost,int sum)
{
    if(cost*sum>=up_bound)
    {
        COMPLETE_PACK(dp,cost);
        return ;
    }

    int k=1;
    while(k<sum)
    {
        ZERO_ONE_PACK(dp,cost*k,k);
        sum -=k;
        k *=2;
    }
    ZERO_ONE_PACK(dp,cost*sum,sum);

}

int main()
{
    while(scanf("%d%d",&n,&m)==2)
    {
        //读取输入+计算上界
        int max_val=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&val[i]);
            max_val= max(max_val,val[i]);
        }
        for(int i=1;i<=n;i++)
            scanf("%d",&num[i]);
        up_bound=max_val*max_val+m;//上界

        //初始化dp和dp2
        for(int i=1;i<=up_bound;i++)
            dp[i]=dp2[i]=INF;
        dp[0]=dp2[0]=0;

        //递推过程
        for(int i=1;i<=n;i++)
        {
            MULTIPLY_PACK(dp,val[i],num[i]);
            COMPLETE_PACK(dp2,val[i]);
        }

        //统计结果
        int ans=INF;
        for(int i=m;i<=up_bound;i++)
            ans= min(ans, dp[i]+dp2[i-m]);
        printf("%d\n",ans==INF?-1:ans);
    }
    return 0;
}
时间: 2024-11-20 17:32:23

POJ 3260 The Fewest Coins(多重背包+全然背包)的相关文章

poj 3260 The Fewest Coins 多重背包+完全背包

题目链接:http://poj.org/problem?id=3260 给店家的钱是多重背包 dp[] 店家的找钱是完全背包 dp2[] 然后最后 其中i表示多给了多少钱 也就是需要找回多少钱 int ans = INF; ans = min(ans, dp[m+i] + dp2[i]); 是一个比较简单的思路 神坑题 看到每种货币的面值不大于120 我就觉得找钱一定不会超过119块钱结果wa到死 后来才发现不是的啊 之所以我有这种思维定式是因为现实生活中有1块钱这种货币单位 考虑一种极限的情况

POJ 3260 The Fewest Coins 最少硬币个数(完全背包+多重背包,混合型)

题意:FJ身上有各种硬币,但是要买m元的东西,想用最少的硬币个数去买,且找回的硬币数量也是最少(老板会按照最少的量自动找钱),即掏出的硬币和收到的硬币个数最少. 思路:老板会自动找钱,且按最少的找,硬币数量也不限,那么可以用完全背包得出组成每个数目的硬币最少数量.而FJ带的钱是有限的,那么必须用多重背包,因为掏出的钱必须大于m,那么我们所要的是大于等于m钱的硬币个数,但是FJ带的钱可能很多,超过m的很多倍都可能,那么肯定要有个背包容量上限,网上说的根据抽屉原理是m+max*max,这里的max指

POJ3260——The Fewest Coins(多重背包+完全背包)

The Fewest Coins DescriptionFarmer John has gone to town to buy some farm supplies. Being a very efficient man, he always pays for his goods in such a way that the smallest number of coins changes hands, i.e., the number of coins he uses to pay plus

HDU 3591 The trouble of Xiaoqian(多重背包+全然背包)

http://acm.hdu.edu.cn/showproblem.php? pid=3591 题意: 有一个具有n种货币的货币系统, 每种货币的面值为val[i]. 如今小杰手上拿着num[1],num[2],-num[n]个第1种,第2种-第n种货币去买价值为T(T<=20000)的商品, 他给售货员总价值>=T的货币,然后售货员(可能,假设小杰给的钱>T,那肯定找钱)找钱给他. 售货员每次总是用最少的硬币去找钱给小杰. 如今的问题是: 小杰买价值T的商品时, 他给售货员的硬币数目+

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

A来B处买东西,价值M元,有N种钱,每种钱A有一定数量,而B有无限数量. 求最少用多少张钞票可以满足交易,比如样例,A出50+25,B找5,即可满足,需要3张. A用多重背包转移状态,B用完全背包. 本文的多重背包优化用的是O(n)算法,二进制转换的O(nlogn)实在懒得写了. 那种可以看http://blog.csdn.net/vmurder/article/details/39472419 " [POJ1014]Dividing 多重背包,二进制物品拆分转01背包 " 贴代码:

B 维背包+完全背包 Hdu2159

<span style="color:#3333ff;">/* ------------------------------------------------------------------------------------------------ author : Grant Yuan time : 2014.7.19 aldorithm: 二维背包+全然背包 ----------------------------------------------------

混合背包(多重背包+完全背包)—— POJ 3260

对应POJ题目:点击打开链接 The Fewest Coins Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 5450   Accepted: 1653 Description Farmer John has gone to town to buy some farm supplies. Being a very efficient man, he always pays for his goods in such a

POJ 1742 Coins (多重背包)

Coins Time Limit: 3000MS   Memory Limit: 30000K Total Submissions: 28448   Accepted: 9645 Description People in Silverland use coins.They have coins of value A1,A2,A3...An Silverland dollar.One day Tony opened his money-box and found there were some

POJ 1742 Coins 多重背包单调队列优化

http://poj.org/problem?id=1742 题意: 很多硬币,有价值和数量,给出一个上限,问上限内有多少种钱数可以由这些硬币组成. 分析: 好像是楼教主男人八题之一.然后学多重背包单调队列优化时看了别人的程序..所以后来写了就1A了=.= 前一篇小小总结了一下多重背包单调队列优化(http://www.cnblogs.com/james47/p/3894772.html),这里就不写了. 1 #include<cstdio> 2 #include<cstring>