从DFS到记忆化DFS到动态规划
什么是动态规划?
动态规划(Dynamic Programming)是通过组合子问题的解来解决问题的。动态规划是用于求解包含重叠子问题的最优化问题的方法。其基本思想是,将原问题分解为相似的子问题。在求解的过程中通过子问题的解求出原问题的解。
动态规划的分类:
1. 线性规划:拦截导弹,合唱队形,挖地雷等。
2. 区域规划:石子合并,加分二叉树,统计单词个数等。
3. 树形动规:贪吃的九头龙,二分查找树,聚会的欢乐等。
4. 背包问题:01背包问题,完全背包问题,分组背包问题,装箱问题,挤牛奶等
5. 除此之外还有插头DP,按位DP,状态压缩DP等等。
入门题目:数字三角形
题目描述:给出了一个数字三角形。从三角形的顶部到底部有很多条不同的路径。对于
每条路径,把路径上面的数加起来可以得到一个和,你的任务就是找到最大的和。
注意:路径上的每一步只能从一个数走到下一层上和它最近的左边的那个数或者右边的那个数。
如:
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
分析一下为什么不能使用贪心算法,即每一次走都走下一行的两个数值较大的。因为有可能在某一步的时候数值小没走到,但是该路径下面有较大的数值,就不会走到,就得不到最大的值。
1.朴素DFS搜索算法
可以采用朴素的深度优先搜索算法,即朴素DFS。每一次走都分为两步,第一步求出走下一步时走的最大值,然后加上此步的数值。
int dfs(int x,int y) //表示从第x行,第y个数往下走可以得到的最大价值和,dfs(0,0)即为本题解。
{
if(x > numCount - )
return ;
return max(dfs(x+,y),dfs(x+,y+)) + num[x][y];
}
完整的代码示例为:
#include
using namespace std;
int num[][] = {,,,,,
,,,,,
,,,,,
,,,,,
,,,,};
int numCount = ;
int dfs(int x,int y)
{
if(x > numCount - )
return ;
return max(dfs(x+,y),dfs(x+,y+)) + num[x][y];
}
int main()
{
int maxsum = ;
maxsum = dfs(,);
cout<<maxsum<<endl;
return ;
}
这个算法效率极低,为什么呢?因为其中有大量的重复计算。通常递归都会有大量的重复计算。
2.DFS+记忆化搜索方法
针对于上述DFS算法的重复计算,我们可以先将dfs(x,y)的结果保存起来,等到下次需要时,直接使用。这就是记忆化搜索。
int dfs(int x,int y)
{
if(x > numCount - )
return ;
if(result[x][y] != -)
return result[x][y];
return result[x][y] = max(dfs(x+,y),dfs(x+,y+)) + num[x][y];
}
完整的代码示例为:
#include
using namespace std;
int num[][] = {,,,,,
,,,,,
,,,,,
,,,,,
,,,,};
int numCount = ;
int result[][];
int dfs(int x,int y)
{
if(x > numCount - )
return ;
if(result[x][y] != -)
return result[x][y];
return result[x][y] = max(dfs(x+,y),dfs(x+,y+)) + num[x][y];
}
int main()
{
for(int i = ;i < ;i++)
for(int j = ; j < ;j++)
result[i][j] = -;
int maxsum = ;
maxsum = dfs(,);
cout<<maxsum<<endl;
return ;
}
不论是DFS还是记忆化DFS都是基于递归的思想进行计算。总结一下实际操作的特点。
(1)搜索的参数只有(x,y),每一对(x,y)确定一个状态。
(2)搜搜的转移是从(x+1,y)和(x+1,y+1)到(x,y)的,意思就是我们通过(x+1,y)和(x+1,y+1)的解去求(x,y)。
于是,设想:如果不用DFS,直接用数组保存状态,在状态与状态之间实现转移。
for(int i = numCount - ; i >= ; i--)
for(int j = ;j <= i; j++)
result[i][j] = max(result[i+][j],result[i+][j+]) + num[i][j];
完整的程序示例为:
#include
using namespace std;
int num[][] = {,,,,,
,,,,,
,,,,,
,,,,,
,,,,};
int numCount = ;
int result[][];
int main()
{
for(int i = ;i < ;i++)
for(int j = ; j < ;j++)
result[i][j] = ;
for(int i = numCount - ; i >= ; i--)
for(int j = ;j <= i; j++)
result[i][j] = max(result[i+][j],result[i+][j+]) + num[i][j];
int maxsum = ;
maxsum = result[][];
cout<<maxsum<<endl;
return ;
}
总结:搜索的参数只有(x,y)。每一对(x,y)确定一个状态。我们通过(x+1,y)和(x+1,y+1)的解去求(x,y),于是我们可以设计出状态并明确状态的转移,从而写出状态转移方程。这就是动态规划!!!!
摘自:http://blog.sina.com.cn/s/blog_8eac84090102vt0y.html
作者:慕雪
从DFS到记忆化DFS到动态规划的更多相关文章
- poj 1088 动态规划+dfs(记忆化搜索)
滑雪 Time Limit:1000MS Memory Limit:65536KB 64bit IO Format:%I64d & %I64u Description Mi ...
- 【poj3252】 Round Numbers (数位DP+记忆化DFS)
题目大意:给你一个区间$[l,r]$,求在该区间内有多少整数在二进制下$0$的数量$≥1$的数量.数据范围$1≤l,r≤2*10^{9}$. 第一次用记忆化dfs写数位dp,感觉神清气爽~(原谅我这个 ...
- HDU1978How Many Ways 记忆化dfs+dp
/*记忆化dfs+dp dp[i][j]代表达到这个点的所有路的条数,那么所有到达终点的路的总数就是这dp[1][1]加上所有他所能到达的点的 所有路的总数 */ #include<stdio. ...
- 滑雪 矩阵中的最长上升路径 /// 记忆化DFS || DP oj22919
大致题意: Description 难怪Michael喜欢滑雪,因为滑雪确实很刺激.为了获得加速度,滑雪道必须向下倾斜,而且当滑到坡底,你不得不再次走上坡或者等待升降机来载你.Michael想知道在一 ...
- 【BZOJ1048】分割矩阵(记忆化搜索,动态规划)
[BZOJ1048]分割矩阵(记忆化搜索,动态规划) 题面 BZOJ 洛谷 题解 一个很简单的\(dp\),写成记忆化搜索的形式的挺不错的. #include<iostream> #inc ...
- *HDU1142 最短路+记忆化dfs
A Walk Through the Forest Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Jav ...
- 最大联通子数组之和(dfs,记忆化搜索,状态压缩)
最大联通子数组,这次的题目,我采用的方法为dfs搜索,按照已经取到的数v[][],来进行搜索过程的状态转移,每次对v[][]中标记为1的所有元素依次取其相邻的未被标记为1的元素,将其标记为1,然而,这 ...
- HDU ACM 1078 FatMouse and Cheese 记忆化+DFS
题意:FatMouse在一个N*N方格上找吃的,每一个点(x,y)有一些吃的,FatMouse从(0,0)的出发去找吃的.每次最多走k步,他走过的位置能够吃掉吃的.保证吃的数量在0-100.规定他仅仅 ...
- 洛谷 P3953 逛公园【spfa+记忆化dfs+bfs】
spfa预处理出最短路数组dis,然后反向建边bfs出ok[u]表示u能到n点 然后发现有0环的话时候有inf解的,先dfs找0环判断即可 然后dfs,设状态f[u][v]为到u点,还可以跑最短路+v ...
随机推荐
- dropout——gluon
https://blog.csdn.net/lizzy05/article/details/80162060 from mxnet import nd def dropout(X, drop_prob ...
- 合并ts到mp4
这个比较好用. copy /b d:\xxx\download_ts\* d:\xxx\download_ts\new.mp4 用python ffmpeg也可以,不过我合出来有卡顿或者掉声问题, ...
- Golang两种执行流程以及区别
Go语言的执行方式有两种,一种是编译后再执行,另一种直接go run执行. 一.先编译后执行 .go文件(源代码)--->go build指令把源代码编译(如果是windows下会编译出一个.e ...
- DGUT_FLY退役贴 && FunCfans毕业总结-竞赛篇
严格来说我们飞跃队是去年ECFinal之后就退役的,只是这几个月有一堆事情在那,考研的考研,求职的求职,都把博客晾一边了.现在,总算能写点东西了. 我与ACM-ICPC的结缘,是从大一开学1个多月后开 ...
- 集合框架-Collection与List集合
对象数组的内存图解: 集合的继承体系图解: * 数组和集合的区别? * A:长度区别 * 数组的长度固定 * 集合长度可变 * B:内容不同 * 数组存储的是同一种类型的元素 * 而集合可以存储不同类 ...
- Jmeter在Linux下执行
1.上传jmeter文件到服务器上(最好自己建一个文件夹:如:mkidr yzb_jmeter) 2.上传jmeter脚本到yzb_jmeter,并修改权限:chmod +x 脚本文件 3.修改统计的 ...
- Python3 tkinter基础 Frame bind 捕捉多键同时按
Python : 3.7.0 OS : Ubuntu 18.04.1 LTS IDE : PyCharm 2018.2.4 Conda ...
- x盒子
0换成1切回
- SpringBoot 通过token进行身份验证,存储redis
代码: public interface TokenManager { /** * 创建token * @param userInfo * @return */ String getToken(Use ...
- 微生物增殖|2012年蓝桥杯B组题解析第一题-fishers
(3')微生物增殖 假设有两种微生物 X 和 Y X出生后每隔3分钟分裂一次(数目加倍),Y出生后每隔2分钟分裂一次(数目加倍). 一个新出生的X,半分钟之后吃掉1个Y,并且,从此开始,每隔1分钟吃1 ...