【动态规划】滚动数组的求解(C++)
虽然接触动态规划算法已经有一段时间,给一个01背包问题,能够做到一个表格简单粗暴下去,然后求得结果,但心里总觉得对这个算法理解十分不到位,抱着对算法的热爱,网上很多大牛的算法思维实在让我佩服的五体投地。在此讲一讲动态规划中滚动数组的求解方法,算是对这个知识点做一个记录,也希望有写的不妥的地方,大家能不吝赐教。
首先,我们先看看“滚动数组”的例题,大家可以参考http://www.lintcode.com/en/problem/house-robber/
题意大概就是说:一个盗贼要去偷盗一系列房子的财物,房子之间有报警器,当且仅当两个相邻的房子同时被偷盗的时候会自动报警,每个房子有一定的价值量,请问盗贼怎么做才能偷到最大价值的量。
求解这类题目要注意以下四点要素(也可以说是动态规划题目的四点要素):
1、状态(State)
用于存储小规模问题的结果
2、方程(Function)
由状态推出的一个方程,即怎么通过小的状态来推出大的状态
3、初始化(Initialization)
最初的状态,作为方程的起点
4、结果(Result)
根据每步的状态求出的结果
回到House-Robber这个题目,这个题目是个典型的滚动数组类型题。给定一个数组,我们不能够取相邻的两个元素,怎么取法可以使取得的结果和最大。比如给定[4,9,1],我们可以取[4,1]或者取[9],很明显一个结果是5,一个结果是9,所以我们这里的结果应该是后者的取法。在状态的确立上,我们可以这么理解,用A[n]数组表示每个元素(下标从0开始),当我们遇到第 i 个元素的时候,我们是取不取,当我们取了第i-1个元素的时候,我们就不能取了,要不就去掉第i-1个元素,以便于取得第i个元素。如果我们用f[n]来代表当遇到第n个元素,我们做出行动(取还是不取)之后,能够获得的最大值,那当取到第i个元素的时候,我们就是判断f[i-2] + A[i]和f[i-1]的大小,然后f[i] = max(f[i-2]+A[i],f[i-1]),你说是不是呢?我们无须去管i-3之前的元素是怎么取的,因为按照这个规律来,在f[i-2]已经包含了到i-2个元素位置能够取得的最大量了。
至此,以上已经阐明了这个思路的【状态】还有【方程】,剩下【初始化状态】和【结果】,我们可以注意到确定第i个方程的结果,往前需要用到i-2的元素,所以第0个元素和第1一个元素需要作为初始化的内容,因为这两个元素均不能用i-2的元素推倒出来,所以有f[0] = A[0],f[1] = max(A[1],A[0])。而结果就是我们对第n-1个元素做出行动之后的结果,该结果存储在f[n-1]当中。
通过代码实现:
long long houseRobber(vector<int> A){
if( == A.size()) return ;
int f[A.size()];
f[] = A[];
if(A.size()>) f[] = max(A[],A[]);
for(int i =;i<A.size();i++)
f[i] = A[i] + f[i-]> f[i-]? A[i] +f[i-]:f[i-];
return f[A.size()-];
}
这样,在时间复杂度O(n)可以求得结果,空间复杂度为O(n)。
【在这里我稍微拓展一下,f[i]的结果是通过对比f[i-2]+A[i]和f[i-1]的结果得来的,那其实i-3及其以前的空间都不需要再用到,所以我们可以只用三个空间重复使用来表示每一个状态,以达到空间复杂度为O(1)】
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
以上就是对一位数组的滚动数组算法求解过程,接下来探讨一下二维数组的滚动数组求解过程,大家可以参考http://www.lintcode.com/en/problem/maximal-square/
题意:给定一个只包含01的二维数组,求出最大的正方形,使这个正方形的所有元素都为1
我们用Matrix[n][m]表示这个二维数组,dp[n][m]表示左上角最大符合条件的正方形边长。首先,四个要素我们先来确定一下。【状态】我们要确定第[i,j]的状态要怎么确定呢,往前推一步有三个状态,分别是[i-1,j],[i,j-1]和[i-1,j-1],这三个状态同样表示了左上角最大的正方形,我们通过图来表示理解一下:
这里为了方便画出了dp[i-1][j],dp[i][j-1],dp[i-1][j-1]相等的情况,可以很容易看出,当dp[i-1][j],dp[i][j-1],dp[i-1][j-1]相等的时候dp[i][j]等于dp[i-1][j],dp[i][j-1],dp[i-1][j-1]其中的一个加上1,如果dp[i-1][j],dp[i][j-1],dp[i-1][j-1]不相等,那dp[i][j]取决于dp[i-1][j],dp[i][j-1],dp[i-1][j-1]之中小的那一个,这里偷懒就不画图了,大家可以自己动手画画看,嘿嘿~。因此【状态】确定了,【方程】也就容易得到dp[i][j] = min(dp[i-1][j],dp[i][j-1],dp[i-1][j-1])+1。【初始化状态】可以想到从[1,1]开始才能应用这个方程(假定我们是从[0,0]向[n,m]逐渐确定状态),所以i=0和j=0都是需要初始化的内容,这种情况下dp[i][j] = Matrix[i][j]。【结果】为dp矩阵中最大值的平方max{dp[n][m]}2。
代码实现:
int maxSquare(vector<vector<int> > &matrix) {
// write your code here
int row = matrix.size();
int col = matrix[].size();
int dp[row][col];
int _max = ;
for(int i =;i<row;i++){
dp[i][] = matrix[i][];
dp[i][col-] = matrix[i][col-];
_max = dp[i][]|dp[i][col-];
}
for(int i =;i<col;i++){
dp[][i] = matrix[][i];
dp[row-][i] = matrix[row-][i];
_max = dp[][i]|dp[row-][i];
}
for(int i =;i<row;i++)
for(int j = ;j<col;j++){
if( == matrix[i][j]) dp[i][j] = min3(dp[i-][j],dp[i][j-],dp[i-][j-]) +;
else dp[i][j] = matrix[i][j];
_max = max(dp[i][j],_max); }
return _max*_max;
}
时间复杂度为O(n*m),空间复杂度为O(n*m)
【拓展:参考一位数组的拓展思路,我们确定[i,j]个状态,分别用到[i-1,j],[i,j-1],[i-1,j-1]这三个状态,所以我们可以想到可以用4个空间来重复表示各个状态,但由于对于二维数组,当换行的时候到了行首会丢失这个状态(因为4个空间在表示上一行末尾的四个状态了),所以我们只能用两行(2*n)个空间来维持这个状态】下面给出拓展后的代码,大家仅供参考,因为初始化状态被写在遍历过程中,可能会造成混乱,请谅解:
int maxSquare(vector<vector<int> > &matrix) {
int row = matrix.size();
int col = matrix[].size();
int dp[][col];
int _max = ;
for(int i =;i<col;i++) dp[][i] = matrix[][i];
for(int i =;i<row;i++)
for(int j=;j<col;j++){
if( == j ) dp[][j] = matrix[i][j];
else{
if( == matrix[i][j]) dp[][j] = min3(dp[][j],dp[][j-],dp[][j-])+;
else dp[][j] = ;
}
_max = max(_max,dp[][j]);
dp[][j-] = dp[][j-];
}
dp[][col-] = dp[][col-];
return _max*_max;
}
这样空间复杂度可以降到O(m)。
以上为个人对滚动数组的求解过程的理解,每一句代码均经过本人测试可用,如有问题,希望大家提出斧正。
尊重知识产权,转载引用请通知作者并注明出处!
【动态规划】滚动数组的求解(C++)的更多相关文章
- 2021.12.10 P2516 [HAOI2010]最长公共子序列(动态规划+滚动数组)
2021.12.10 P2516 [HAOI2010]最长公共子序列(动态规划+滚动数组) https://www.luogu.com.cn/problem/P2516 题意: 给定字符串 \(S\) ...
- 动态规划+滚动数组 -- POJ 1159 Palindrome
给一字符串,问最少加几个字符能够让它成为回文串. 比方 Ab3bd 最少须要两个字符能够成为回文串 dAb3bAd 思路: 动态规划 DP[i][j] 意味着从 i 到 j 这段字符变为回文串最少要几 ...
- POJ_1159 Palindrome (线性动态规划+滚动数组)
题意是说,给定一个字符串,问至少还需要插入多少个字符才能使得该字符串成为回文字符串. 这道题一开始做的时候用了一个简单的动态规划,开了一个5000*5000的数组,用递归形式实现,代码如下: 其中d[ ...
- HDU-1024 Max Sum Plus Plus 动态规划 滚动数组和转移优化
题目链接:https://cn.vjudge.net/problem/HDU-1024 题意 给n, m和一个序列,找m个不重叠子串,使这几个子串内元素和的和最大. n<=1e6 例:1 3 1 ...
- HDOJ-1024(动态规划+滚动数组)
Max Sum Plus Plus HDOJ-1024 动态转移方程:dp[i][j]=max(dp[i][j-1]+a[j],max(dp[i-1][k])+a[j]) (0<k<j) ...
- HDU-10240Max Sum Plus Plus+动态规划+滚动数组
Max Sum Plus Plus 题意:题意理解了老半天,这里是说在给定数列中,取m组子数列,不能有重复,使得这些子序列的和最大: 就比如m=2时候,1 /2/-4/5/6.可以不用拿-4的意思: ...
- nyoj--1184--为了肾六(动态规划+滚动数组)
为了肾六 时间限制:4000 ms | 内存限制:210535 KB 难度:2 描述 最近肾六很流行,goshawk看身边的朋友都用上了apple.自己还用着W年前的Samsung.于是决定去IT ...
- POJ-1038 Bugs Integrated, Inc. (状压+滚动数组+深搜 的动态规划)
本题的题眼很明显,N (1 <= N <= 150), M (1 <= M <= 10),摆明了是想让你用状态压缩dp. 整个思路如下:由于要填2*3或者3*2的芯片,那么就要 ...
- 动态规划(入门,滚动数组,记录的都是状态):SWUSTACM-1010 魔兽争霸之最后的反击
题目: 1010: 魔兽争霸之最后的反击 Time Li ...
随机推荐
- Linux显示登录Shell信息
Linux显示登录Shell信息 youhaidong@youhaidong-ThinkPad-Edge-E545:~$ finger -p Login Name Tty Idle Login Tim ...
- devDependencies和dependencies的版本写法
devDependencies和dependencies的版本写法 指定版本:比如1.2.2,遵循大版本.次要版本.小版本的格式规定,安装时只安装指定版本. 波浪号(tilde)+指定版本:比如~1. ...
- Unity3d开发中与oc交互之类型转换
对于非科班出身的程序来说,在没有学过C和OC的情况,用unity开发iOS相关的功能,是非常痛苦的.简单写一下自己遇到的,并且没有百度到的坑. 1.C#给OC传递字典 一般流程是,C#调用C,C调用O ...
- 畅通工程 HDU - 1863
省政府"畅通工程"的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可).经过调查评估,得到的统计表中列出了有可能建设公路的若干条道 ...
- 一篇关于PHP性能的文章
一篇关于PHP性能的文章 昨晚清理浏览器收藏夹网址时,发现了http://www.phpbench.com/,想起来应该是2015年发现的一个比较性能的文章,我就点进去看了看,发现还是全英文耶,刚好最 ...
- jQuery UI Autocomplete Combobox 配 ASP.NET DropDownList
0.引言 1.起因 一开始使用Autocomplete做了一个自动补全的文本框,如上图.后来因业务需要希望能在这个文本框的边上做个下拉列表按钮,一按就展开所有支持 ...
- php 数组排序得方法
$sort1 = array_column($list_bloc[1], 'value');//按照$list_bloc[1]里面的value做降序排序 array_multisort($sort1, ...
- NgRx/Store 4 + Angular 5使用教程
这篇文章将会示范如何使用NgRx/Store 4和Angular5.@ngrx/store是基于RxJS的状态管理库,其灵感来源于Redux.在NgRx中,状态是由一个包含action和reducer ...
- 【NOIP2016】【CJOJ2257】2257 愤怒的小鸟
题目 Description https://www.luogu.org/problem/show?pid=2831 Kiana最近沉迷于一款神奇的游戏无法自拔. 简单来说,这款游戏是在一个平面上进行 ...
- 【NOIP2012】疫情控制(二分,倍增,贪心)
洛谷上的题目链接,题目不在赘述 题解 既然要时间最短,首先考虑二分. 因此,考虑二分时间,问题转换为如何检查能否到达. 如果一支军队一直向上走,能够到达根节点,那么他可以通过根节点到达其他的节点,因此 ...