动态规划进阶篇
来源:互联网 发布:联通软件研究院 亦庄 编辑:程序博客网 时间:2024/05/29 15:59
动态规划进阶篇
如果你已经熟悉了动态规划的基础知识,那么接下来我们来讨论二维的动态规划吧!
问题:
给定一个
解决这个问题与其它的DP问题并没有其它的区别。
首先,我们要找到问题的“状态”。我们要注意的是我们最多有两种状态去收集苹果:从左边(除了第一列)和从右边(除了第一行)。因此为了求出到达当前格子后最多能收集到多少个苹果, 我们就要先去考察那些能到达当前这个格子的格子,到达它们最多能收集到多少个苹果。 (是不是有点绕,但这句话的本质其实是DP的关键:欲求问题的解,先要去求子问题的解)
经过上面的分析,很容易得出问题的状态S[i][j]表示到达格子(i, j)最多能收集到苹果的个数。那么状态转换方程为:
其中
伪代码:
For i = 0 to N - 1 For j = 0 to M - 1 S[i][j] = A[i][j] + max(S[i][j-1], if j>0 ; S[i-1][j], if i>0 ; 0)Output S[n-1][m-1]
LintCode 数字三角形
首先来一道简单的题,练练手。
题目描述
给定一个数字三角形,找到从顶部到底部的最小路径和。每一步可以移动到下面一行的相邻数字上。样例比如,给出下列数字三角形:[ [2], [3,4], [6,5,7], [4,1,8,3]]从顶到底部的最小路径和为11 ( 2 + 3 + 5 + 1 = 11)。
对于动态规划问题,首先我们要找到问题的“状态”和“状态转换方程”。
对于该问题我们假设dp[i][j]为从第1行元素到第i行第j个元素的最小路径和。比如说
因为到达元素(i, j)只能从上面相邻的元素到达,因此有:
注意:下标从0开始
Talk is cheap, show me thecode!
int minimumTotal(vector<vector<int> > &triangle){ int n = triangle.size(); //行数 vector<vector<int>> dp(n); // 创建一个N行的二维数组 dp[0].push_back(triangle[0][0]); // 从第二行元素开始,因为第一行只有一个元素 for (int i = 1; i < n; ++i) { int col = triangle[i].size(); //第i行的元素个数。。。其实 col = i+1; vector<int> tmp(col, 0); for (int j = 0; j < col; ++j) { // 注意边界条件 if (j == 0) tmp[j] = triangle[i][j] + dp[i-1][j]; else if (j == col -1 ) tmp[j] = triangle[i][j] + dp[i-1][j-1]; else tmp[j] = triangle[i][j] + min(dp[i-1][j], dp[i-1][j-1]); } dp[i] = tmp; } int res = dp[n-1][0]; for (int i = 1; i < dp[n-1].size(); ++i) { res = min(res,dp[n-1][i]); } return res;}
TopCoder AvoidRoads
Problem Statement
In the city, roads are arranged in a grid pattern. Each point on the grid represents a corner where two blocks meet. The points are connected by line segments which represent the various street blocks. Using the cartesian coordinate system, we can assign a pair of integers to each corner as shown below.
You are standing at the corner with coordinates 0,0. Your destination is at corner width,height. You will return the number of distinct paths that lead to your destination. Each path must use exactly width+height blocks. In addition, the city has declared certain street blocks untraversable. These blocks may not be a part of any path. You will be given a String[] bad describing which blocks are bad. If (quotes for clarity) “a b c d” is an element of bad, it means the block from corner a,b to corner c,d is untraversable. For example, let’s say
width = 6
length = 6
bad = {“0 0 0 1”,”6 6 5 6”}
The picture below shows the grid, with untraversable blocks darkened in black. A sample path has been highlighted in red.
Constraints
- width will be between 1 and 100 inclusive.
- height will be between 1 and 100 inclusive.
- bad will contain between 0 and 50 elements inclusive.
- Each element of bad will contain between 7 and 14 characters inclusive.
- Each element of the bad will be in the format “a b c d” where,
a,b,c,d are integers with no extra leading zeros,
a and c are between 0 and width inclusive,
b and d are between 0 and height inclusive,
and a,b is one block away from c,d.
- The return value will be between 0 and 2^63-1 inclusive.
Examples
0)
6
6
{“0 0 0 1”,”6 6 5 6”}
Returns: 252
Example from above.
1)
1
1
{}
Returns: 2
Four blocks aranged in a square. Only 2 paths allowed.
2)
35
31
{}
Returns: 6406484391866534976
Big number.
3)
2
2
{“0 0 1 0”, “1 2 2 2”, “1 1 2 1”}
Returns: 0
先来看一下题目说了啥吧。给定一个
注意:“Each path must use exactly width+height blocks”, 因此给定一个坐标到下一个坐标只能往右或者往上走。
动态规划问题的解法只有两个步奏:找到问题的“状态”和“状态转换方程”。
对于这个问题如果说所有的网格线都是可以走的通的话,那么个问题与上面收集苹果的问题,有木有感觉解法是一样的!!!!
首先,我们要知道问题的状态:假设从坐标(0,0)走到左边(i, j)一共有
因为走到坐标
因此,现在关键的问题变成判断
Talk is cheap, show me the code!
#include<iostream>#include<string>#include<vector>#include<algorithm>using namespace std;//将坐标解析成字符串string parse(int x, int y, int i, int j) { string str; str = string(1,x+'0') + " " + string(1, y+'0') + " "; str += string(1,i+'0') + " " + string(1, j+'0'); return str;}/* brief: 判断从坐标的左边(x-1, y)或者下面(x, y-1)是否可以到达坐标(x, y)*param x, y :坐标(x, y)*param bad: 不通的路径*param str: 取"Left"表示判断从(x-1, y)到(x,y)是否为通。"Down"表示从下面**/bool canReach(int x, int y, vector<string> &bad, string str){ int i = x, j = y; if (str == "Left") i = x-1; if (str == "Down") j = y - 1; auto iter = find(bad.begin(), bad.end(), parse(i, j, x, y)); if (iter != bad.end()) { //说明该路径不可达 // 该路径我们已经使用过了,则我们可以删除提高查找效率 bad.erase(iter); return false; } //注意题目中的陷阱 else if ((iter = find(bad.begin(), bad.end(), parse(x, y,i,j))) != bad.end()) { bad.erase(iter); return false; } return true;}/** brief: 判断从坐标(0,0)到坐标(width, height)有多少种路径*param bad: 不同的路径坐标*/long long numWays(int width, int height, vector<string> bad){ // 创建一个二维数组并且初始化为0 vector<vector<long long>> dp(width+1, vector<long long>(height+1, 0)); dp[0][0] = 1; //边界条件 for (int i = 0; i <= width; ++i) { for (int j = 0; j <= height; ++j) { if (i > 0 && canReach(i, j, bad, "Left")) dp[i][j] += dp[i-1][j]; if (j > 0 && canReach(i, j, bad, "Down")) dp[i][j] += dp[i][j-1]; } } return dp[width][height];}int main(){ vector<string> bad {"0 0 0 1","6 6 5 6"}; cout << numWays(6, 6, bad) << endl; return 0;}
Reference:
[1] 动态规划:从新手到专家
[2] Dynamic Programming – From Novice to Advanced
- 动态规划进阶篇
- 动态规划进阶
- 动态规划-进阶
- 动态规划进阶
- 动态规划初步进阶(一)
- 算法进阶之动态规划
- 教你彻底学会动态规划——进阶篇
- 教你彻底学会动态规划——进阶篇
- 教你彻底学会动态规划——进阶篇
- 【动态规划进阶-背包型】钱币系统
- 动态规划进阶题目之滑雪
- HDU 4734 浅谈数位动态规划进阶
- 04动态规划进阶---背包问题
- 夕拾算法进阶篇:12)出栈序列统计(动态规划DP)
- 夕拾算法进阶篇:13)最大连续子序列(动态规划DP)
- 夕拾算法进阶篇:14)最长上升子序列(动态规划DP)
- 夕拾算法进阶篇:15)最长公共子序列(动态规划DP)
- 夕拾算法进阶篇:16)最长回文子串(动态规划DP)
- 把Emacs配置成C++和LaTeX环境
- 端口号扫描工具---nmap
- 互联网专家资源分享(一)
- unix学习笔记------msgctl函数的使用
- Chrome Native Messaging技术示例
- 动态规划进阶篇
- 使用Qt开发中国象棋(四):步时控制
- Ubuntu server 15.0.4安装Redis cluster
- UVa 10082 WERTYU
- 视觉SLAM漫淡
- JS 的this、new、apply和call详解
- macvim 不能输入中文问题
- CodeForces 128B [ 后缀树 ]
- 引用Drawable颜色常数及背景色