poj_3260 动态规划
题目大意
顾客拿着N种硬币(币值为value[i], 数量为c[i])去买价值为T的东西,商店老板也有同样N种币值的硬币,但是数量不限。顾客买东西可能需要用硬币找零来使得花出去的钱为T,求顾客给老板的硬币数为count1,老板找回给顾客的硬币数目为count2,求count1 + count2的最小值。
题目分析
先通过求和得到顾客的总钱数,若小于T,则说明无法进行交换,直接返回-1;否则,可以进行交换,那么顾客给老板的总钱数V1肯定>=T, 而老板找回给顾客的总钱数为 V1 - T.
用顾客手上的硬币去凑成V1的钱,为多重背包问题,通过转换为01背包来解决。这样可以求得 f1[V1] 表示用顾客手上的硬币凑成价值为V1的钱的硬币的最小数目;用老板手上的硬币去凑成V2的钱,为一个完全背包问题,利用完全背包来解决,得到f2[V2]表示用老板手上的硬币凑成价值为V2的钱的硬币的最小数目。
然后对V1进行遍历,找到V1-V2 = T,且f[V1]+f[V2]最小的f[V1]+f[V2]即可。
需要注意的是初始化
实现(c++)
#define _CRT_SECURE_NO_WARNINGS
//思路是 将要付的钱t 表示成 s1 - s2的形式,其中s1为顾客要给老板的钱数;s2为老板找回的钱数
//s1 >= t,否则无效
//两个dp数组f1, f2,其中 f1[i] 表示 顾客用身上的硬币凑成 i元所消耗的最少硬币数目
//f2[i] 表示老板要找i元所消耗的最少硬币数目
//由于顾客硬币数目有限制,为01背包; 老板硬币数目无限制,为完全背包 #include<stdio.h>
#include<string.h>
#define MAX_CENTS 20200
#define COIN_TYPE_NUM 102
#define INFINITE 1 << 28
int gCoinValue[MAX_CENTS]; //将多重背包转换为01背包之后的硬币的币值
int gCoinNum[MAX_CENTS]; //将多重背包转换为01背包之后每个硬币值代表的实际硬币个数 int f1[MAX_CENTS];
int f2[MAX_CENTS]; //多重背包转01背包,二进制优化
//将数字n分解为 集合S{1, 2, 4, 。。。2^(k-1), n - 2^k + 1}
//数字[1,n]内的任何数字都可以用集合S中的多个数字拼成
//其中k为满足 n - 2^k + 1 > 0的最大的k
void Expand(int v, int n, int& index){
int k = 1;
do{
gCoinNum[index] = k;
gCoinValue[index++] = k*v;
k *= 2; } while (2*k < n);
gCoinNum[index] = (n - k + 1);
gCoinValue[index++] = (n - k + 1)*v;
}
int min(int a, int b){
return a < b ? a : b;
} int main(){
int n, t, index = 0;
int coin_value[COIN_TYPE_NUM];
scanf("%d %d", &n, &t);
for (int i = 0; i < n; i++){
scanf("%d", coin_value + i);
}
int coin_num, sum_value = 0;
for (int i = 0; i < n; i++){
scanf("%d", &coin_num);
sum_value += coin_num*(coin_value[i]);
Expand(coin_value[i], coin_num, index);
}
if (sum_value < t){ //直接判断,总的钱数是否够物品价值,不够则直接返回失败
printf("-1\n");
return 0;
} memset(f1, 0, sizeof(f1));
memset(f2, 0, sizeof(f2));
int m = t + MAX_CENTS / 2; //范围,猜测的。。。 //进行合理的初始化
for (int i = 0; i <= m; i++){
f1[i] = f2[i] = INFINITE;
} f1[0] = 0; //一个硬币都没有,能够构成总价值为0的最少 硬币数目为0
f2[0] = 0; f1[gCoinValue[0]] = 1; //用前1个硬币进行初始化,即用前1种硬币凑成 coin_value[0] 价值的硬币的最少数目
f2[coin_value[0]] = 1; for (int i = 1; i < index; i++){ //多重背包转换为01背包,利用前一个物品初始化之后,从前2个物品开始循环
for (int w = m; w >= gCoinValue[i]; w--){
f1[w] = min(f1[w], f1[w - gCoinValue[i]] + gCoinNum[i]);
}
} for (int i = 0; i < n; i++){ //完全背包,从前1个物品开始
for (int w = coin_value[i]; w <= m - t; w++){
f2[w] = min(f2[w], f2[w - coin_value[i]] + 1);
}
}
int min_coin_num = INFINITE;
for (int i = t; i <= m; i++){
min_coin_num = min(min_coin_num, f1[i] + f2[i - t]);
}
if (min_coin_num == INFINITE) //判断是否能够 拼成 t
printf("-1\n");
else
printf("%d\n", min_coin_num);
return 0;
}
poj_3260 动态规划的更多相关文章
- 增强学习(三)----- MDP的动态规划解法
上一篇我们已经说到了,增强学习的目的就是求解马尔可夫决策过程(MDP)的最优策略,使其在任意初始状态下,都能获得最大的Vπ值.(本文不考虑非马尔可夫环境和不完全可观测马尔可夫决策过程(POMDP)中的 ...
- 简单动态规划-LeetCode198
题目:House Robber You are a professional robber planning to rob houses along a street. Each house has ...
- 动态规划 Dynamic Programming
March 26, 2013 作者:Hawstein 出处:http://hawstein.com/posts/dp-novice-to-advanced.html 声明:本文采用以下协议进行授权: ...
- 动态规划之最长公共子序列(LCS)
转自:http://segmentfault.com/blog/exploring/ LCS 问题描述 定义: 一个数列 S,如果分别是两个或多个已知数列的子序列,且是所有符合此条件序列中最长的,则 ...
- C#动态规划查找两个字符串最大子串
//动态规划查找两个字符串最大子串 public static string lcs(string word1, string word2) { ...
- C#递归、动态规划计算斐波那契数列
//递归 public static long recurFib(int num) { if (num < 2) ...
- 动态规划求最长公共子序列(Longest Common Subsequence, LCS)
1. 问题描述 子串应该比较好理解,至于什么是子序列,这里给出一个例子:有两个母串 cnblogs belong 比如序列bo, bg, lg在母串cnblogs与belong中都出现过并且出现顺序与 ...
- 【BZOJ1700】[Usaco2007 Jan]Problem Solving 解题 动态规划
[BZOJ1700][Usaco2007 Jan]Problem Solving 解题 Description 过去的日子里,农夫John的牛没有任何题目. 可是现在他们有题目,有很多的题目. 精确地 ...
- POJ 1163 The Triangle(简单动态规划)
http://poj.org/problem?id=1163 The Triangle Time Limit: 1000MS Memory Limit: 10000K Total Submissi ...
随机推荐
- c# 高效的线程安全队列ConcurrentQueue
c#高效的线程安全队列ConcurrentQueue<T>(上) c# 高效的线程安全队列ConcurrentQueue(下) Segment类 c#高效的线程安全队列Concurrent ...
- 解决CentOS7 无法启动mysql 的解决办法
MariaDB数据库管理系统是MySQL的一个分支,主要由开源社区在维护,采用GPL授权许可.开发这个分支的原因之一是:甲骨文公司收购了MySQL后,有将MySQL闭源的潜在风险,因此社区采用分支的方 ...
- hibernate 中多对多关系对象集合的保存
多对多关系映射和一对多关系映射开发步骤差不多, 例子如下:员工和项目之间的关系,一个员工可以参与多个项目:一个项目可以有多个开发人员参与.因此是多对多的关系. 1 分析数据表 1.1)员工表 CREA ...
- 雅虎天气API调用
雅虎天气API调用: 1.调用方法:http://weather.yahooapis.com/forecastrss?w=2502265&u=c,绿色字体为城市代号,u=c表示取摄氏度. 2. ...
- 详解php的安装模式---CGI,FASTCGI,php-fpm,mod_php,mod_cgi,mod_fcgid
1. CGI CGI是通用网关接口,HTTP服务器使用这样的接口程序来和“其他程序”(比如PHP的解释器程序)通讯,这个“其他程序”可以使用任何计算机语言来编写,它通过CGI这个接口从HTTP服务器取 ...
- Atitit.ALT+TAB没反应车and 点击任务栏程序闪烁但是不能切换
Atitit.ALT+TAB没反应车and 点击任务栏程序闪烁但是不能切换 1. 可能你的Alt+Tab键被别人禁用了,试下下面的方法: 1 2. 为什么要禁用Alt+Tab 1 3. ALT+TAB ...
- 查询ip地址归属地
查询ip地址归属地方法: curl ip.cn/$ip 如果没有返回,试试地址写全: curl https://www.ip.cn/$ip 如:
- 2、Reactive Extensions for .NET(译)
实验3-引入 .net 中的 events 到 Rx 目标:前面实验中的使用各种工厂构造方法创建一个 可观察序列是一个部分.把 .net 中现有的异步数据源进行关联 是更重要的事情.在这次实验中我们将 ...
- Python 实现抽象类的两种方式+邮件提醒+动态导入模块+反射(参考Django中间件源码)
实现抽象类的两种方式 方式一 from abc import ABCMeta from abc import abstractmethod class BaseMessage(metaclass=AB ...
- private继承的作用
这里有个demo,里面的Stack<T*> : private Stack<void *>,作者对此的解释如下 The partial specialization for o ...