关于他们的思想,这里就不再罗嗦了,直接 show you my code ,看题讨论 。

题目1:自然是最最经典的塔类问题啦(数字之塔 )

有如下所示的数塔,要求从顶层走到底层,若每一步只能走到相邻的结点,则经过的结点的数字之和最大是多少?

Input
输入数据首先包括一个整数C,表示数据的个数。
每个测试实例的第一行是一个整数N(1 <= N <= 100),表示数塔的高度,接下来用N行数字表示数塔,其中第i行有个i个整数,且所有的整数均在区间[0,99]内。
Output
对于每个测试实例,输出可能得到的最大和,每个实例的输出占一行。
Sample Input
1
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
Sample Output
30

解题思路:这类问题从塔的底层开始看起,从倒数第二层计算找到一个最大的和(倒数第二层与倒数第一层左右的和),比如:在这道题中,可以找到( 21,9,25,28,19,13,9,21),那么倒数第二层就会变成了(21,28,19,21)可以看出是目前从10->18最优,依次类推,下一步就会得到(31,38,34,25,27,29),那么倒数第三层就变成了(38,34,29),再下一步得到(50,46,49,44),,那么倒数第四层就变成了(50,49),以此类推即可。重点就是(局部最优,不一定整体最优)

#include <iostream>
#include <string.h>
#include<algorithm>
using namespace std;
#define TT 200 //整数 N(1 <= N <= 100),表示数塔的高度
int F[TT][TT];
int DP(int row)
{for (int i = row - 2; i >= 0; i--){for (int j = 0; j <= i; j++)F[i][j] = max(F[i][j] + F[i + 1][j], F[i][j] + F[i + 1][j + 1]);}return F[0][0];
}
int main(void)
{int C, N;while (cin >> C) {for (int i = 0; i < C; i++){memset(F, -1, sizeof(F));cin >> N;                   for (int j = 1; j <= N; j++) {for (int k = 0; k < j; k++) cin >> F[j - 1][k];}cout << DP(N) << endl;}}
}

题目2:B - 兑换硬币 + (DP || 数学)

在某个国家,只有 1 元、2 元和 3 元面值的三种硬币。现在你持有 N 元,想
把它全部兑换为硬币,请问有多少种兑换方法呢?

输入
输入的数据有多组,每组数据在一行内有一个正整数 N。

输出
对于每组数据,在一行内输出将 N 元换成硬币的方法数。

样例输入
2934
12553

样例输出
718831
13137761

DP 方法求解:

思路:递推即可

#include <iostream>
#include <vector>
using namespace std;
int DP(int amount)
{vector<int> F(amount + 1, 1);for (int i = 2; i <= 3; ++i){for (int j = i; j <= amount; ++j){F[j] += F[j - i];  //F[k]表示的兑换方法数}}return F[amount];
}
int main(void)
{int N = 0;while (cin >> N){cout << DP(N) << endl;}return 0;
}

数学方法求解:有了数学,真的可以为所欲为。这句话真的没有一点毛病。先上AC代码看看:

#include <iostream>
#include <vector>
using namespace std;
int main(void)
{int N = 0;int temp ,Sum ,MM ;while (cin >> N){temp = N / 3; //不仅表示有多少个三,还表示有3和1的组合的种类与多少种Sum = N / 3 + 1;  // +1代表什么?代表用 1 所构成的兑换方法数for (int i = 0; i <= temp; ++i){MM = (N - i * 3) / 2; /*  “/2”是什么意思?  *//* 代表用2和1的组合去换拿掉一个3时剩下的数,可是,这又是为什么呐?为什么要拿掉一个三?不拿掉其他的?*/ Sum += MM;}cout << Sum << endl;}return 0;
}

情景叙述:这里我们就以10元钱为例,10元可以只由3和1的组合构成10/3种([3,3,3,1],[3,3,111,1],[3,111,111,1]),而由1构成的只有一种([111,111,111,1]),当然,在这时,我们也知道了它有多少(N/3)个三,这时我们求它只由2和1构成的数量(N/2),然后我们拿出来一个三(其实就是这个三不变了,其余的用2和1的组合代替),以此类推,我们再拿出来一个三,再拿出来一个三,再拿出来一个三,直到把三拿完即可。

PS:感觉这个结论,是具有普适性的,以后遇到再进行更加一步的证明。有待论证。

题目3,4:都是最长公共子序列的变式,以前写过,这里就不说了 。不会的可以点 这里

题目5:E - 超级跳跃 Remake

输入
输入的数据有多组,每组数据首先是两个正整数 N 和 M (1 ≤ N, M ≤ 100)
表示在一个 N × N 的区域内进行游戏,且超级跳跃只能移动到距离为 M 的区
域中。接下来有 N 行,每行有 N 个以空格为分dp
若 N 和 M 均cout << 等,表示输入结束,每组数据,在一行内输出一个正整数,表示游戏中可获得的最大价值。

样例输入
3 1
1 2 5
10 11 6
12 12 7
-1 -1

样例输出
37 */

解题思路:DFS+DP。DFS通过递归的手段从后向前找寻答案,而我们一般的DP从前向后寻找答案。这道题则采用 DFS+DP(记忆化搜索)的手段去解决。当前状态的值等于 Max(下一个状态1,下一个状态2,下一个状态3,下一个状态4 。。。)这里需要通过递归获得。

DP[i][j] 表示的就是从[i][j] 点开始所能吃到的最大奶酪数
#include <iostream>
#include <string.h>
#include <algorithm>
using namespace std;
const int TT = 101;
int map[TT][TT] = {0};
int dp[TT][TT] = {0};
/*用dp[i][j]表示以(i,j)为起点进行dfs的结果,从而下次扫到(i,j)时就不需要再扫一遍了。*/
int M = 0, N = 0;
int dir[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; //右,下,左,上
bool check(int x, int y, int xx, int yy)
{if (xx < 0 || xx > N || yy < 0 || yy > N)return false;if (map[xx][yy] <= map[x][y]) // 判断条件return false;return true;
}
int DFS(int x, int y)
{if (dp[x][y] > 0)return dp[x][y];int result = 0;for (int i = 0; i < 4; i++){for (int j = 1; j <= M; j++){int xx = x + dir[i][0] * j;int yy = y + dir[i][1] * j;if (check(x, y, xx, yy)){result = max(result, DFS(xx, yy));//printf("result ==  %d \n", result);}}}dp[x][y] = result + map[x][y];//从dp[x][y]开始能吃到的最大奶酪量/*可以走各个点的最大值中最大的那个+当前点的数值 = 当前点的最大值*/printf("dp[%d][%d] == %d\n", x, y, dp[x][y]);return dp[x][y];
}
int main(void)
{while (cin >> N >> M){if (N == -1 && M == -1)return 0;memset(map, 0, sizeof(map));memset(dp, 0, sizeof(dp));for (int i = 0; i < N; i++){for (int j = 0; j < N; j++){cin >> map[i][j];}}cout << DFS(0, 0) << endl;}
}

记忆化搜索与DP的区别:

  1. DP是从下向上,而记忆化搜索是从上向下的

  2. DP是从下向上,为了求到最终结果需要把过程中所有的值都保存下来,以便下一步可能会使用,而因为记忆化搜索是从上向下的,所以求解过程求的都是需要的;也就是说不需要的值并没有求

  3. 记忆化搜索使用递归实现的,而DP是使用迭代实现的

如果一个dp[i][j]的值已经求过,使用DP直接调用即可;而使用记忆化搜索则要进入递归中去求,而这个递归很有可能是多重的

题目6:F - 超级跳跃 2 + 排队问题

广受好评的《超级跳跃》游戏终于出了新作品,你作为它的粉丝已经迫不及
待的想要购买了。当你到达电玩店时,发现店前已经排起了长队,加上你一
共有 N 个人之多!每个人单独购买自己所需要的产品所需 Ki 秒,也可以选择
和排在自己前面的那个人合作,这样的话则需要 Si 秒。现在是早上 8 点,若
这 N 个人采用了最快的方式买完了自己所需的产品,那么买完的时候是什么
时间呢?

输入
输入的数据首先是一个整数 C,表示有 C 组输入数据。每组数据首先是一个
正整数 N(1 ≤ N ≤ 10),然后在下一行内有 N 个整数 K1,K2 … KN,表示 N
个人单独购买需要的时间,接下来有 N – 1 个整数 S1,S2 … SN-1,表示每个
人和前面那个人一起购买需要的时间。

输出
对于每组数据,在一行内输出 N 个人最快在何时全部完成购买。
输出格式为 HH:MM:SS am/pm,如开始时间就表示为 08:00:00 am,下午 2
时则表示为 14:00:00 pm。

样例输入
2
2
20 25
40
1
8

样例输出
08:00:40 am
08:00:08 am

解题思路:状态转移方程叙述:第n个人所用的时间就是 Min(前一个人所用的时间+第n个人单独用的时间,前n-2个人所用的时间+第n-1个人和第n个人时间和)

#include <iostream>
#include <string.h>
#include <algorithm>
#include <climits>
using namespace std;
const int TT = 2000;
int F[2][TT] = {0}; // 2 行 ,最大是 N 列
int dp[TT] = {0};
int DP(int n)
{dp[0] = F[1][0];dp[1] = min(F[0][0], dp[0] + F[1][1]);for (int i = 2; i < n; i++)dp[i] = min(dp[i - 1] + F[1][i], dp[i - 2] + F[0][i - 1]);/*状态转移方程叙述:第n个人所用的时间就是 Min(前一个人用的时间+第n个人单独用的时间,前n-2个人所用的时间+第n-1个人和第n个人的时间和)*/return dp[n - 1];
}
int main(void)
{int C, N;while (cin >> C){for (int k = 0; k < C; k++){cin >> N;memset(F, 0, sizeof(F));for (int i = 0; i < N; i++)cin >> F[1][i];for (int j = 0; j < N - 1; j++)cin >> F[0][j];int temp = DP(N);int second = temp % 60;int hour = temp / 60 / 60 + 8;temp = temp / 60;int minutes = temp % 60;if (hour >= 12)printf("%02d:%02d:%02d pm\n", hour, minutes, second);elseprintf("%02d:%02d:%02d am\n", hour, minutes, second);}}
}

动态规划(DP)01相关推荐

  1. 动态规划DP——01背包问题

    01 背包问题   今天在算法课上讲解了动态规划算法,其中讲到了01背包问题.这是一种典型的动态规划问题,于是下课之后我使用java进行了相对应的代码实现.动态规划求解具有以下的性质: 1.最优子结构 ...

  2. 动态规划dp(带模板题の超易懂版):01背包,完全背包,分组背包,多重背包,混合背包

    动态规划dp(带模板题の超易懂版):01背包,完全背包,分组背包,多重背包 01背包 && 完全背包 && 分组背包 の 视频教程:https://www.bilibi ...

  3. 经典动态规划:0-1 背包问题

    经典动态规划:0-1 背包问题 文章目录 经典动态规划:0-1 背包问题 一.题目描述 二.动规标准套路 三.题目描述 四.解法分析 五.优化 一.题目描述 就讨论最常说的 0-1 背包问题,简单描述 ...

  4. 动态规划: dp+递推——确定动态矩阵dp含义,确定每个状态下面临的选择和对结果值影响,选择符合题意的作为结果存储在dp中

    1.动态规划:每一个状态一定是由之前的状态推导出来的,通过总结归纳发现递推关系 2.解决动态规划问题的步骤: 确定dp数组(dp table)以及下标的含义: 每个单元内 题目所求的值,一维.二维 确 ...

  5. o-1背包问题迭代_经典动态规划:01背包问题的变体

    点击上方蓝字设为星标 东哥带你手把手撕力扣~ 作者:labuladong   公众号:labuladong 若已授权白名单也必须保留以上来源信息 上篇文章 经典动态规划:0-1 背包问题 详解了通用的 ...

  6. 算法模板:动态规划之01背包【沈七】

    算法模板:动态规划之01背包 前言 动态规划 01背包 二维背包 一维优化 经典习题 小A点菜 5 倍经验日 买干草 完结散花 参考文献 前言 唤我沈七就好啦. 动态规划 核心作用:优化 当数据范围& ...

  7. 0-1背包问题 动态规划java_C#使用动态规划解决0-1背包问题实例分析

    // 利用动态规划解决0-1背包问题 using System; using System.Collections.Generic; using System.Linq; using System.T ...

  8. 第4课 防卫导弹(第十章 动态规划--DP)

    //progream p10_04 /* 第4课 防卫导弹(第十章 动态规划--DP)  (<聪明人的游戏--信息学探秘 提高篇>) https://blog.csdn.net/weixi ...

  9. 动态规划解决0-1背包问题详解(图文并茂)

    动态规划解决0-1背包问题 这个是网上比较好的案例,因为原文有些地方晦涩难懂,对于刚接触动态规划问题的朋友来说很不友好,所以很对地方加入了我自己的见解,也是作为我的一次学习历程. 一.问题描述: 有n ...

  10. 【习题详解】动态规划DP:硬币游戏 蛋糕 游荡的奶牛 决斗

    动态规划DP 硬币 蛋糕塔 游荡的奶牛 格斗 硬币 题目描述 农夫约翰的奶牛喜欢玩硬币游戏,因此他发明了一种称为"Xoinc"的两人硬币游戏. 初始时,一个有N(5 <= N ...

最新文章

  1. javascript中作用域,优先级等等问题, 求助中。。。。。。。。
  2. php 下载脱离服务器,php – 强制从外部服务器下载并重命名
  3. Ubuntu中清理Network下Connect to Server的入口
  4. Oracle conn 协议适配器错误解决
  5. m3u8手机批量转码_手机怎么把m3u8格式转换成mp4格式?
  6. mysql 把主键当外键_MySQL主键和外键使用及说明
  7. 零基础学python要多久-零基础如何学Python?小白学Python需要多久?
  8. 中文怎么设置 水晶报表 越南文_越南语到底是不是汉语的一门方言?为什么和粤语这么像?...
  9. STM32-GPIO的配置和使用
  10. Apache CarbonData学习资料汇总
  11. 一次LoadLibrary调用失败的调试经历
  12. 实时文件同步工具-端端Clouduolc在项目研发中的使用体会
  13. 不改变图片分辨率,减少图片存储大小
  14. python比赛积分类算法题_python常用算法题
  15. rocksdb 安装全过程 一些问题解决方法
  16. airpod蓝牙耳机音量大解决办法_关于AirPods的常见问题汇总 全面了解苹果AirPods无线耳机...
  17. CANoe.DiVa 操作指南 -TP层测试
  18. 基于Flask的就诊预约系统的设计与实现
  19. Navicat Preium 中文版破解
  20. 微信小程序实现图片拖动、放大、缩小、旋转、滤镜和切图功能

热门文章

  1. FCPX:快速时尚视频转场Stupid Raisins Fast Pop下载
  2. win10系统运行sh脚本
  3. EFM32芯片被锁解决方法
  4. 重估2020:“黑天鹅”催生的AI新业态
  5. Python常用设计模式—创建型模式
  6. 烽火HG680-KA-MV300/310-刷机固件及教程
  7. (转)计算机领域的顶级会议和期刊
  8. 电脑死机故障解决方法全面汇总
  9. 深度迅雷5.8.3.556无广告绿色超级精简版【迅雷6核心文件】-绿软下载
  10. 颜色的前世今生20·三原色到底该用哪一个?!