硬币问题  

  有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 “是否被访问过”

记忆化搜索代码如下:

  1. #include<cstdio>
  2. #include<cstdlib>
  3. #include<algorithm>
  4. using namespace std;
  5. const int maxn = , maxv = ;
  6. int n, S, v[maxn], mind[maxv], maxd[maxv];
  7. int dp1(int s) //最小值
  8. {
  9. int &ans = mind[s];
  10. if(ans != -) return ans;
  11. ans = <<;
  12. for(int i = ; i <= n; ++i) if(v[i] <= s) ans = min(ans, dp1(s-v[i])+);
  13. return ans;
  14. }
  15. int vis[maxv];
  16. int dp2(int s) //最大值
  17. {
  18. if(vis[s]) return maxd[s];
  19. vis[s] = ;
  20. int &ans = maxd[s];
  21. ans = -<<;
  22. for(int i = ; i <= n; ++i) if(s >= v[i]) ans = max(ans, dp2(s-v[i])+);
  23. return ans;
  24. }
  25. void print_ans(int* d, int s) //打印的是边
  26. {
  27. for(int i = ; i <= n; ++i) if(v[i] <= s && d[s-v[i]]+ ==d[s])
  28. {
  29. printf("%d ",i);
  30. print_ans(d, s-v[i]);
  31. break;
  32. }
  33. }
  34. int main()
  35. {
  36. freopen("9-3.in", "r", stdin);
  37. scanf("%d%d", &n, &S);
  38. for(int i = ; i <= n; ++i) scanf("%d", v+i);
  39. memset(mind, -, sizeof(mind));
  40. mind[] = ;
  41. printf("%d\n", dp1(S));
  42. print_ans(mind, S);
  43. printf("\n");
  44. memset(maxd, -, sizeof(maxd));
  45. memset(vis, , sizeof(vis));
  46. maxd[] = ;
  47. vis[] = ;
  48. printf("%d\n", dp2(S));
  49. print_ans(maxd, S);
  50. printf("\n");
  51. return ;
  52. }

递推代码如下:

  1. #include <cstdio>
  2. #include <cstring>
  3. const int maxn = , maxv = , INF = ;
  4. int v[maxn], S, n, maxf[maxv], minf[maxv], min_coin[maxv], max_coin[maxv];
  5. void print_ans(int *d, int s){
  6. while(s){
  7. printf("%d ", d[s]);
  8. s-=v[d[s]];
  9. }
  10. }
  11. int main(){
  12. freopen("9-3.in", "r", stdin);
  13. scanf("%d%d", &n, &S);
  14. for(int i = ; i <= n; ++i) scanf("%d", &v[i]);
  15. for(int i = ; i <= S; ++i) {
  16. //最应注意的是边界条件、初始化,因为递推作为重点一般不会写错,就是在这种细节处出错
  17. maxf[i] = -INF;
  18. minf[i] = INF;
  19. }
  20. maxf[] = minf[] = ;
  21. for(int i = ; i <= S; ++i)
  22. for(int j = ; j <= n; ++j) if(i >= v[j]){
  23. if(maxf[i-v[j]] + > maxf[i]){
  24. maxf[i] = maxf[i-v[j]] + ;
  25. max_coin[i] = j;
  26. }
  27. if(minf[i-v[j]] + < minf[i]){
  28. minf[i] = minf[i-v[j]] + ;
  29. min_coin[i] = j;
  30. }
  31. }
  32. printf("%d\n", minf[S]);
  33. print_ans(min_coin, S);
  34. printf("\n");
  35. printf("%d\n", maxf[S]);
  36. print_ans(max_coin, S);
  37. printf("\n");
  38. return ;
  39. }

不必打印路径代码:

  1. #include<cstdio>
  2. #include<cstdlib>
  3. const int maxn = , maxv = , INF = ;
  4. int n, S, v[maxn], min[maxv], max[maxv];
  5. int main(){
  6. scanf("%d%d", &n, &S);
  7. for(int i = ; i <= n; ++i) scanf("%d", v+i);
  8. min[] = max[] = ;
  9. for(int i = ; i <= S; ++i) {min[i] = INF; max[i] = -INF;}
  10. for(int i = ; i <= S; ++i)
  11. for(int j = ; j <= n; ++j) if(v[j] <= i){
  12. if(min[i-v[j]] + < min[i]) min[i] = min[i-v[j]] + ;
  13. if(max[i-v[j]] + > max[i]) max[i] = max[i-v[j]] + ;
  14. }
  15. printf("%d\n", min[S]);
  16. printf("%d\n", max[S]);
  17. return ;
  18. }

DAG模型——硬币问题的更多相关文章

  1. UVA103 dp基础题,DAG模型

    1.UVA103 嵌套n维空间 DAG模型记忆化搜索,或者 最长上升子序列. 2.dp[i]=max( dp[j]+1),(第i个小于第j个) (1) //DAG模型记忆化搜索 #include< ...

  2. NYOJ16|嵌套矩形|DP|DAG模型|记忆化搜索

    矩形嵌套 时间限制:3000 ms  |  内存限制:65535 KB 难度:4   描述 有n个矩形,每个矩形可以用a,b来描述,表示长和宽.矩形X(a,b)可以嵌套在矩形Y(c,d)中当且仅当a& ...

  3. DAG模型

    数字三角形: 1.递归计算 int solve(int i,int j) { :max(solve(i+,j),solve(i+,j+))); } 2.记忆化搜索,不用指明计算顺序,并且保证每个状态只 ...

  4. DAG模型——嵌套矩阵

    有向无环图上的动态规划是学习动态规划的基础,很多问题都可以转化为DAG上的最长路.最短路或路径计数问题. 嵌套矩阵 有n个矩阵,每个矩阵可以用两个整数a,b描述,表示它的长和宽.矩阵X(a,b)可以嵌 ...

  5. DAG动态规划-硬币问题

    题目:有n种硬币,面值分别为V1,V2,...Vn,每种都有无限多.给定非负整数S,可以选用多少个硬币,使得面值之和恰好为S?输出硬币数目的最小值和最大值! #include <bits/std ...

  6. DAG 模型 stacking boxes 动态规划

    题目:UVA 103 stacking boxes 题目大意: 给你两个数,一个是盒子的个数,一个是每一个盒子的维数.将一个个盒子互相装起来,让你求最多可以装多少个,要求字典序最小. 解析:这个就是盒 ...

  7. DAG模型(矩形嵌套)

    推荐在线例题:http://acm.nyist.net/JudgeOnline/problem.php?pid=16 题摘: 矩形嵌套 时间限制:3000 ms  |  内存限制:65535 KB 难 ...

  8. DP入门(2)——DAG上的动态规划

    有向无环图(DAG,Directed Acyclic Graph)上的动态规划是学习动态规划的基础.很多问题都可以转化为DAG上的最长路.最短路或路径计数问题. 一.DAG模型 [嵌套矩形问题] 问题 ...

  9. 第九章(二)DAG上的动态规划

    DAG上的动态规划: 有向无环图上的动态规划是学习DP的基础,很多问题都可以转化为DAG上的最长路.最短路或路径计数问题. 1.没有明确固定起点重点的DAG模型: 嵌套矩形问题:有n个矩形,每个矩形可 ...

随机推荐

  1. HW3.6

    import java.util.Scanner; public class Solution { public static void main(String[] args) { Scanner i ...

  2. Android Studio 导入项目错误

    Gradle DSL method not found: 'Android()' 错误原因: android studio 引进项目时,自动查找本机是否有项目设置的SDK版本,若发现没有,我们会在pr ...

  3. ffmpeg关于aac解码

    ffmpeg从0.11.3版本开始,默认解码aac为AV_SAMPLE_FMT_FLT (float) 0.11.2以前版本解码aac为AV_SAMPLE_FMT_S16 (16位short型)

  4. A list of base boxes for Vagrant - Vagrantbox.es

    Create image server with nginx + lua (Openresty) + graphicsmagick (Part I) | Ian's PhotograPhy Blog ...

  5. Windows Service中使用Threading.Timer需注意回收

    在Windows Service中使用Threading.Timer时需要注意回收池问题 Threading.Timer是基于线程池的,系统会对其进行垃圾回收. 当Threading.Timer定义在 ...

  6. PC-经典之“运行里面的密密”

    msconfig.exe 你自己往里面输入这个字母就可以看到了,试试看,还有,我这里有一些可以在"运行"栏里输入的命令,一并给你: 以下为Windows操作系统的常用运行命令,执行 ...

  7. hdoj 2803 The MAX【简单规律题】

    The MAX Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Sub ...

  8. em与px之间的换算

    任意浏览器的默认字体高度16px(16像素).所有未经调整的浏览器都符合:1em=16px.那么12px=0.75em,10px=0.625em.为了简化font-size的换算,需要在css中的bo ...

  9. eclipse调试的基本意义

    step into就是单步执行,遇到子函数就进入并且继续单步执行: step over是在单步执行时,在函数内遇到子函数时不会进入子函数内单步执行,而是将子函数整个执行完再停止,也就是把子函数整个作为 ...

  10. [C#]工具类—FTP上传下载

    public class FtpHelper { /// <summary> /// ftp方式上传 /// </summary> public static int Uplo ...