DAG模型——硬币问题
硬币问题
有n种硬币,面值分别为V1,V2,...,Vn,每种都有无限多。给定非负整数S,可以选用多少个硬币,使得面值之和恰好为S?输出硬币数目的最小值和最大值。1<=n<=100, 0<=S<=10000,1<=Vi<=S.
分析:
我们把每种面值看做一个点,表示“还需要凑足的面值”,则初始状态为S,目标状态为0.若当前在状态 i ,每使用一个硬币j ,状态便转移到 i-Vj .
注意到最长路和最短路的求法是类似的,下面只考虑最长路。由于终点固定,d(i)的确切含义变为“从结点i出发到结点0的最长路径长度”
在记忆化搜索中,如果用特殊值表示“还没算过”,则必须将其和其他特殊值(比如无解)区分开。
也可以不用特殊值表示还没算过,而是用另外一个数组vis[i]表示状态i “是否被访问过”
记忆化搜索代码如下:
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int maxn = , maxv = ;
int n, S, v[maxn], mind[maxv], maxd[maxv];
int dp1(int s) //最小值
{
int &ans = mind[s];
if(ans != -) return ans;
ans = <<;
for(int i = ; i <= n; ++i) if(v[i] <= s) ans = min(ans, dp1(s-v[i])+);
return ans;
}
int vis[maxv];
int dp2(int s) //最大值
{
if(vis[s]) return maxd[s];
vis[s] = ;
int &ans = maxd[s];
ans = -<<;
for(int i = ; i <= n; ++i) if(s >= v[i]) ans = max(ans, dp2(s-v[i])+);
return ans;
}
void print_ans(int* d, int s) //打印的是边
{
for(int i = ; i <= n; ++i) if(v[i] <= s && d[s-v[i]]+ ==d[s])
{
printf("%d ",i);
print_ans(d, s-v[i]);
break;
}
}
int main()
{
freopen("9-3.in", "r", stdin);
scanf("%d%d", &n, &S);
for(int i = ; i <= n; ++i) scanf("%d", v+i);
memset(mind, -, sizeof(mind));
mind[] = ;
printf("%d\n", dp1(S));
print_ans(mind, S);
printf("\n");
memset(maxd, -, sizeof(maxd));
memset(vis, , sizeof(vis));
maxd[] = ;
vis[] = ;
printf("%d\n", dp2(S));
print_ans(maxd, S);
printf("\n");
return ;
}
递推代码如下:
#include <cstdio>
#include <cstring>
const int maxn = , maxv = , INF = ;
int v[maxn], S, n, maxf[maxv], minf[maxv], min_coin[maxv], max_coin[maxv];
void print_ans(int *d, int s){
while(s){
printf("%d ", d[s]);
s-=v[d[s]];
}
}
int main(){
freopen("9-3.in", "r", stdin);
scanf("%d%d", &n, &S);
for(int i = ; i <= n; ++i) scanf("%d", &v[i]);
for(int i = ; i <= S; ++i) {
//最应注意的是边界条件、初始化,因为递推作为重点一般不会写错,就是在这种细节处出错
maxf[i] = -INF;
minf[i] = INF;
}
maxf[] = minf[] = ;
for(int i = ; i <= S; ++i)
for(int j = ; j <= n; ++j) if(i >= v[j]){
if(maxf[i-v[j]] + > maxf[i]){
maxf[i] = maxf[i-v[j]] + ;
max_coin[i] = j;
}
if(minf[i-v[j]] + < minf[i]){
minf[i] = minf[i-v[j]] + ;
min_coin[i] = j;
}
}
printf("%d\n", minf[S]);
print_ans(min_coin, S);
printf("\n");
printf("%d\n", maxf[S]);
print_ans(max_coin, S);
printf("\n");
return ;
}
不必打印路径代码:
#include<cstdio>
#include<cstdlib>
const int maxn = , maxv = , INF = ;
int n, S, v[maxn], min[maxv], max[maxv];
int main(){
scanf("%d%d", &n, &S);
for(int i = ; i <= n; ++i) scanf("%d", v+i);
min[] = max[] = ;
for(int i = ; i <= S; ++i) {min[i] = INF; max[i] = -INF;}
for(int i = ; i <= S; ++i)
for(int j = ; j <= n; ++j) if(v[j] <= i){
if(min[i-v[j]] + < min[i]) min[i] = min[i-v[j]] + ;
if(max[i-v[j]] + > max[i]) max[i] = max[i-v[j]] + ;
}
printf("%d\n", min[S]);
printf("%d\n", max[S]);
return ;
}
DAG模型——硬币问题的更多相关文章
- UVA103 dp基础题,DAG模型
1.UVA103 嵌套n维空间 DAG模型记忆化搜索,或者 最长上升子序列. 2.dp[i]=max( dp[j]+1),(第i个小于第j个) (1) //DAG模型记忆化搜索 #include< ...
- NYOJ16|嵌套矩形|DP|DAG模型|记忆化搜索
矩形嵌套 时间限制:3000 ms | 内存限制:65535 KB 难度:4 描述 有n个矩形,每个矩形可以用a,b来描述,表示长和宽.矩形X(a,b)可以嵌套在矩形Y(c,d)中当且仅当a& ...
- DAG模型
数字三角形: 1.递归计算 int solve(int i,int j) { :max(solve(i+,j),solve(i+,j+))); } 2.记忆化搜索,不用指明计算顺序,并且保证每个状态只 ...
- DAG模型——嵌套矩阵
有向无环图上的动态规划是学习动态规划的基础,很多问题都可以转化为DAG上的最长路.最短路或路径计数问题. 嵌套矩阵 有n个矩阵,每个矩阵可以用两个整数a,b描述,表示它的长和宽.矩阵X(a,b)可以嵌 ...
- DAG动态规划-硬币问题
题目:有n种硬币,面值分别为V1,V2,...Vn,每种都有无限多.给定非负整数S,可以选用多少个硬币,使得面值之和恰好为S?输出硬币数目的最小值和最大值! #include <bits/std ...
- DAG 模型 stacking boxes 动态规划
题目:UVA 103 stacking boxes 题目大意: 给你两个数,一个是盒子的个数,一个是每一个盒子的维数.将一个个盒子互相装起来,让你求最多可以装多少个,要求字典序最小. 解析:这个就是盒 ...
- DAG模型(矩形嵌套)
推荐在线例题:http://acm.nyist.net/JudgeOnline/problem.php?pid=16 题摘: 矩形嵌套 时间限制:3000 ms | 内存限制:65535 KB 难 ...
- DP入门(2)——DAG上的动态规划
有向无环图(DAG,Directed Acyclic Graph)上的动态规划是学习动态规划的基础.很多问题都可以转化为DAG上的最长路.最短路或路径计数问题. 一.DAG模型 [嵌套矩形问题] 问题 ...
- 第九章(二)DAG上的动态规划
DAG上的动态规划: 有向无环图上的动态规划是学习DP的基础,很多问题都可以转化为DAG上的最长路.最短路或路径计数问题. 1.没有明确固定起点重点的DAG模型: 嵌套矩形问题:有n个矩形,每个矩形可 ...
随机推荐
- 分布式搜索Elasticsearch增、删、改、查操作深入详解
引言: 对于刚接触ES的童鞋,经常搞不明白ES的各个概念的含义.尤其对“索引”二字更是与关系型数据库混淆的不行.本文通过对比关系型数据库,将ES中常见的增.删.改.查操作进行图文呈现.能加深你对ES的 ...
- 跟我一起学extjs5(05--主界面上增加顶部和底部区域)
跟我一起学extjs5(05--主界面上增加顶部和底部区域) 这一节为主界面加一个顶部区域和底部区域. 一个管理系统的界面能够粗分为顶部标题部分.中间数据展示和处理的部分.底部备注和状 ...
- careercup-树与图 4.1
4.1 实现一个函数,检查二叉树是否平衡.在这个问题中,平衡树的定义如下:任意一个结点,其两颗子树的高度差不超过1. C++实现代码: #include<iostream> #includ ...
- VC++深入详解-第二章学习心得
由于之前看过C++的一些知识,所以这一章就挑一点以前比较不太在意的进行记录 首先是虚函数,纯虚函数 虚函数用关键字virtual申明,我理解成为派生类提供覆盖 纯虚函数virtual xxx()=xx ...
- phpcms 源码分析三:common.inc.php
这次是逆雪寒分析common.inc.php的数据库部分: <?php // 包含数据库操作类,下章详说 require PHPCMS_ROOT.'/include/'.$db_file.'.c ...
- 整理 iOS 9 适配中出现的坑
本文主要是说一些iOS9适配中出现的坑,如果只是要单纯的了解iOS9新特性可以看瞄神的开发者所需要知道的 iOS 9 SDK 新特性.9月17日凌晨,苹果给用户推送了iOS9正式版,随着有用户陆续升级 ...
- 测试浏览器最多能包含Cookie的个数和Cookie中包含的最多内容
public class CookieTestServlet extends HttpServlet { public void doGet(HttpServletRequest request, H ...
- hdu1016JAVA
import java.util.Arrays;import java.util.Scanner;public class Main { public static int kase=0,n; pub ...
- DirectShow初探
filtergraphmanagernullmicrosoftdirect3d 可能到现在为止,还没有哪个玩过游戏的人没有接触过Microsoft的DirectX的.因为现今大多数的游戏都是用Dire ...
- (原创)speex与wav格式音频文件的互相转换(二)
之前写过了如何将speex与wav格式的音频互相转换,如果没有看过的请看一下连接 http://www.cnblogs.com/dongweiq/p/4515186.html 虽然自己实现了相关的压缩 ...