从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 ...
随机推荐
- js 迭代方法
迭代方法 * every():对数组中的每一项运行给定函数,如果该函数对每一项都返回true,则返回true. * filter():对数组中的每一项运行给定函数,返回该函数会返回true 的项组成的 ...
- 前端页面报net::ERR_CONNECTION_RESET错误的原因
本机和测试环境都是OK的.但是一到线上就报错:可能原因总结如下: 1 可能是服务器限制了文件上传的权限. 解决方法:开通了文件上传权限. 2 也许导致这种错误的方式有很多,可能是因为post请求时提交 ...
- nmap扫描验证多种漏洞
nmap在Kali Linux中是默认安装的.它不仅可以用来确定目标网络上计算机的存活状态,而且可以扫描各个计算机的操作系统.开放端口.服务,还有可能获得用户的证书. 命令结构: nmap -sS - ...
- 使用Holer外网SSH访问内网(局域网)Linux系统
1. Holer工具简介 Holer exposes local servers behind NATs and firewalls to the public internet over secur ...
- window.open()居中显示
function openwindow(url,name,iWidth,iHeight){ // url 转向网页的地址 // name 网页名称,可为空 // iWidth 弹出窗口的宽度 // i ...
- select2 AJAX获取数据
页面效果: index.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"& ...
- js的匿名函数 和普通函数
匿名函数在声明时不用带上函数名, 可以把匿名函数当作一个function类型的值来对待 声明一个普通的函数 function func() { ... } 可以认为和var func = functi ...
- docker 给运行的容器映射本地端口
1.提交运行中的容器为一个镜像 (这样不会丢失在容器的各种操作) docker commit tang tang1 ### tang(运行容器名称) tang1(生成镜像名称) 2 ...
- Item的anchors属性
1.anchors group: anchors.top : AnchorLine anchors.bottom : AnchorLine anchors.left : AnchorLine anch ...
- Oracle错误——SP2-0734: 未知的命令开头 "imp C##sin..." - 忽略了剩余的行。
错误 在windows的DOS窗口下使用命令导入Oracle数据. 原因 进入sqlplus里是不能执行imp的(sqlplus不认识imp),imp 是个工具,应该在cmd的dos命令提示符下执行.