POJ1742 coins 动态规划之多重部分和问题

原题链接:http://poj.org/problem?id=1742

题目大意:tony现在有n种硬币,第i种硬币的面值为A[i],数量为C[i]。现在tony要使用这些硬币去买一块价格不超过m的表。他希望买的时候不用找零,问有多少种价格能满足这一点。

这个问题实际上是一个多重部分和的问题:假设有n种物品,每种物品的价值为v[i],数量为c[i],随意选取这些物品,能否使它们的价值之和恰好为m。使用动态规划的思想来求解这类问题:

定义dp数组,dp[i][j]的值代表前i种物品随意选取,价值之和为j时第i种物品最多能剩下多少个,当前i种物品无法使价值之和刚好为j时,其值为-1。那么,很明显,递推关系存在四种情况:

①:如果dp[i - 1][j] >= 0,也就是说前i - 1种物品已经可以组合得到j,此时第i种物品可以一件也不取,即dp[i][j] = c[i];

②:如果不满足情况①,那么我们要通过在第i种物品中选取来使价值之和为j,但如果j的值小于v[i]的话,哪怕只选取一个也会超过j,所以此时无法实现要求,dp[i][j] = -1;

③:如果不满足情况①且j又不小于v[i]时,也许我们可以通过选取a个第i种物品来使价值之和恰好为j(1 <= a)。如果可以的话,那么选取a - 1个一定可以使价值之和为j - v[i],所以dp[i][j]可以由dp[i][j - v[i]]推出。如果dp[i][j - v[i]]等于-1(无法实现)或者等于0(第i种物品已用完),dp[i][j]都等于-1;

④:在情况③中,如果在第i种中拿a个能使价值之和为j - v[i],且第i种物品还有剩余,那再拿一个就可以使价值之和为j了,即dp[i][j] = dp[i][j - v[i]] - 1。

有了这些递推关系,我们就可以用如下的代码来求解多重部分和问题:

int n;//物品种数
int m;//目标和
int v[n];//每种物品的价值
int c[n];//每种物品的数量
memset(dp, -1, sizeof(dp));
dp[0] = 0;//初始化
for(int i = 0;i < n;i++)
{
    for(int j = 0;j <= m;j++)
    {
        if(dp[j] >= 0)//情况①
         {
             dp[j] = c[i];
             //这里滚动使用了一个一维数组,dp[j]在更新前代表的是上一轮的值(即二维的dp[i - 1][j])或初始值
         }
        else if(j < v[i] || dp[j - v[i]] <= 0)//情况②、③
        {
            dp[j] = -1;
        }
        else//情况④
        {
            dp[j] = dp[j - v[i]] - 1;
        }
    }
}

这道poj1742只是在上面这个问题的基础上略加变形,我们只需要遍历dp数组求出1-m中有多少中价格可以被组合出来即可得到答案。

不过这种解法在POJ上耗时1800ms左右,虽然可以ac,但可能无法应付更大的数据规模或者更高的效率要求,我们还可以借助二进制优化或者各种数据结构来进一步提高效率。

原文地址:https://www.cnblogs.com/sun-of-Ice/p/9307276.html

时间: 2024-11-05 12:21:58

POJ1742 coins 动态规划之多重部分和问题的相关文章

多重部分和 poj1742

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 coins.He decided to buy a very nice watch in a nearby shop. He wanted to pay the exact pri

编程算法 - 多重部分和问题 代码(C)

多重部分和问题 代码(C) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 有n种不同大小的数字a, 每种各m个. 判断是否可以从这些数字之中选出若干使它们的和恰好为K. 使用动态规划求解(DP), 方法1: dp[i+1][j] = 用前n种数字是否能加和成j, 时间复杂度O(nKm), 不是最优. 方法2: dp[i+1][j] = 用前i种数加和得到j时, 第i种数最多能剩余多少个. 时间复杂度O(nK). 例如: n=3, a={3,5,8},

POJ1742 Coins(男人八题之一)

前言 大名鼎鼎的男人八题,终于见识了... 题面 http://poj.org/problem?id=1742 分析 § 1 多重背包 这很显然是一个完全背包问题,考虑转移方程: DP[i][j]表示用前i种硬币能否取到金额j,ture表示可以,false表示不行. 则有 DP[i][j] = DP[i - 1][j] | DP[i - 1][j - k * Ai], 0 ≤ k ≤ Ci, j - k * Ai ≥ 0 这是一个O(N3)的算法,考虑到数据范围1 ≤ N ≤ 100, M ≤

HDU1059——多重部分和问题——Dividing

Problem Description Marsha and Bill own a collection of marbles. They want to split the collection among themselves so that both receive an equal share of the marbles. This would be easy if all the marbles had the same value, because then they could

COJ 0557 4013多重部分和问题

4013多重部分和问题 难度级别:B: 运行时间限制:2000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 n种大小不同的数字 Ai,每种各Mi个,判断是否可以从这些数字之中选出若干个使他们的和恰好为K. 输入 第一行为两个正整数n,K.第二行为n个数Ai,以空格隔开.第三行为n个数Mi,以空格隔开. 输出 若可行则输出"yes"否则输出"no" 输入示例 3 173 5 83 2 2 输出示例 yes 其他说明 1<=n

14年省赛---多重部分和问题(多重背包+二进制优化)

1210: F.多重部分和问题 时间限制: 1 Sec  内存限制: 64 MB提交: 18  解决: 14 题目描述 有n种不同大小的数字,每种各个.判断是否可以从这些数字之中选出若干使它们的和恰好为K. 输入 首先是一个正整数T(1<=T<=100)接下来是T组数据 每组数据第一行是一个正整数n(1<=n<=100),表示有n种不同大小的数字 第二行是n个不同大小的正整数ai(1<=ai<=100000)第三行是n个正整数mi(1<=mi<=100000

【动态规划】多重背包

贵有恒,何必三更起五更眠:最无益,莫过一日曝十日寒. [动态规划]多重背包 时间限制: 1 Sec  内存限制: 64 MB提交: 5  解决: 5[提交][状态][讨论版] 题目描述 张琪曼:“魔法石矿里每种魔法石的数量看起来是足够多,但其实每种魔法石的数量是有限的.” 李旭琳:“所以我们需要改变装包策略啦.” 现有N(N≤10)种魔法石和一个容量为V(0<V<200)的背包.第i种魔法石最多有n[i]件可用,每个占用的空间是c[i],价值是w[i].全部物品总数不超过50.求解将哪些魔法石

POJ1742 Coins[多重背包可行性]

Coins Time Limit: 3000MS   Memory Limit: 30000K Total Submissions: 34814   Accepted: 11828 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

poj1742 Coins【多重背包】【贪心】

Coins Time Limit: 3000MS   Memory Limit: 30000K Total Submissions:43969   Accepted: 14873 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