FZU 1432 Problem 1432 Coin Changing(多重背包变形DP)

42 篇文章 1 订阅
19 篇文章 2 订阅

 Problem 1432 Coin Changing

Accept: 358    Submit: 1017
Time Limit: 1000 mSec    Memory Limit : 32768 KB

 Problem Description

There are n kinds of coins. Given the available number of coins for each kind, you are to calculate the minimal number of coins needed to exchange m yuan. 

 Input

There are several test cases. The fist line of each case contains an integer n (1<=n<=10). Followed n lines, each line contains two integers representing the cost and the available number of coins of this kind respectively. The last line of each case contains an integer m (1<=m<=20001) representing the given amount of money you have to exchange. 

 Output

Please output the minimal number of coins needed to exchange the money. If you can't exchange the given amount of money, please output -1.

 Sample Input

31 32 35 318

 Sample Output

5

 Source

FZU 2006 Summer Training II
再来看看FZU 1432
题目大意:给你几种硬币,问用这些硬币换成一定金额,求最少用多少硬币能够换成.
例如:
1 3
2 3
5 3
这三种面额的硬币,要换成18.
则最优解是,5*3+2*1+1*1    需要5枚硬币
思路:
同样可以将其转化成背包问题.但是要求的并不是最大价值,而是达到背包容量,但是却使用的件数最少。
所以递推式应该变化.相应的dp初始值也需要变化。
 dp[j] = min(dp[j], dp[j-w[i]]+v[i]);
这里的v[i]也就变成了用的硬币个数,w就是硬币的价值,换成背包问题就是  w就是重量,v就是价值,这道题目要求背包装满,要价值最小,所以状态转移就是上面那个了;很巧妙的用到了背包的方式。。。数据量比较大,所以用二进制


#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxn = 3e4 + 5;
const int INF = 1e9;
int v[maxn], dp[maxn], w[maxn];
int main()
{
    int n, m;
    while(~scanf("%d", &n))
    {
        int a, b, index = 1;
        for(int i = 1; i <= n; i++)
        {
            scanf("%d%d", &a, &b);
            for(int j = 1; j <= b; j <<= 1)
            {
                w[index] = j * a;
                v[index++] = j;
                b -= j;
            }
            if(b)
            {
                w[index] = b * a;
                v[index++] = b;  //这里记录的是多少个硬币
            }
        }
        scanf("%d", &m);
        for(int i = 1; i <= m; i++) dp[i] = INF;  //因为求最小值,所以要把其余的变成+无穷
        dp[0] = 0;  //0为0,这样后面的不是正无穷的说明是“填满的”,这种初始化方式有许多变通的
        for(int i = 1; i < index; i++)
        {
            for(int j = m; j >= w[i]; j--)
            {
                dp[j] = min(dp[j], dp[j-w[i]]+v[i]);
            }
        }
        if(dp[m] != INF)  //能装满说明就可以换成
            printf("%d\n", dp[m]);
        else
            printf("-1\n");
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值