虽然接触动态规划算法已经有一段时间,给一个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++)的更多相关文章

  1. 2021.12.10 P2516 [HAOI2010]最长公共子序列(动态规划+滚动数组)

    2021.12.10 P2516 [HAOI2010]最长公共子序列(动态规划+滚动数组) https://www.luogu.com.cn/problem/P2516 题意: 给定字符串 \(S\) ...

  2. 动态规划+滚动数组 -- POJ 1159 Palindrome

    给一字符串,问最少加几个字符能够让它成为回文串. 比方 Ab3bd 最少须要两个字符能够成为回文串 dAb3bAd 思路: 动态规划 DP[i][j] 意味着从 i 到 j 这段字符变为回文串最少要几 ...

  3. POJ_1159 Palindrome (线性动态规划+滚动数组)

    题意是说,给定一个字符串,问至少还需要插入多少个字符才能使得该字符串成为回文字符串. 这道题一开始做的时候用了一个简单的动态规划,开了一个5000*5000的数组,用递归形式实现,代码如下: 其中d[ ...

  4. HDU-1024 Max Sum Plus Plus 动态规划 滚动数组和转移优化

    题目链接:https://cn.vjudge.net/problem/HDU-1024 题意 给n, m和一个序列,找m个不重叠子串,使这几个子串内元素和的和最大. n<=1e6 例:1 3 1 ...

  5. 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) ...

  6. HDU-10240Max Sum Plus Plus+动态规划+滚动数组

    Max Sum Plus Plus 题意:题意理解了老半天,这里是说在给定数列中,取m组子数列,不能有重复,使得这些子序列的和最大: 就比如m=2时候,1 /2/-4/5/6.可以不用拿-4的意思: ...

  7. nyoj--1184--为了肾六(动态规划+滚动数组)

    为了肾六 时间限制:4000 ms  |  内存限制:210535 KB 难度:2 描述 最近肾六很流行,goshawk看身边的朋友都用上了apple.自己还用着W年前的Samsung.于是决定去IT ...

  8. POJ-1038 Bugs Integrated, Inc. (状压+滚动数组+深搜 的动态规划)

    本题的题眼很明显,N (1 <= N <= 150), M (1 <= M <= 10),摆明了是想让你用状态压缩dp. 整个思路如下:由于要填2*3或者3*2的芯片,那么就要 ...

  9. 动态规划(入门,滚动数组,记录的都是状态):SWUSTACM-1010 魔兽争霸之最后的反击

    题目: 1010: 魔兽争霸之最后的反击                                                                         Time Li ...

随机推荐

  1. 芝麻HTTP:Scrapy-Splash的安装

    Scrapy-Splash是一个Scrapy中支持JavaScript渲染的工具,本节来介绍它的安装方式. Scrapy-Splash的安装分为两部分.一个是Splash服务的安装,具体是通过Dock ...

  2. 版本控制工具--svn和git的使用(三) -----git的使用(1)

    安装 git官网就有git各个系统的安装包,可以根据自己系统安装相应的安装包.window的git安装包 依据国内网速原因,将安装放到网盘里,链接: https://pan.baidu.com/s/1 ...

  3. Word巧用大纲视图 快速重排版面

    对于由于内容顺序混乱而造成的目录顺序不当的文章,通常我们一定会想到先对文档内容进行手工排序,然后重新提取目录.但这样操作显然麻烦,而且也容易出错.对于从正文内容自动提取出来的目录,由于按住Ctrl键单 ...

  4. xml的SAX解析和dom解析的区别

    一,区别 DOM解析 SAX解析 原理: 一次性加载xml文档,不适合大容量的文件读取 原理: 加载一点,读取一点,处理一点.适合大容量文件的读取 DOM解析可以任意进行增删改成 SAX解析只能读取 ...

  5. cookie的初步认识

    一.会话的概念 会话可简单理解为:用户开一个浏览器,点击多个超链接,访问服务器多个web资源,然后关闭浏览器,整个过程称之为一个会话. 有状态会话:一个同学来过教室,下次再来教室,我们会知道这个同学曾 ...

  6. WPF基础篇之系统中141种颜色

    WPF最大的特点就是酷炫的外观,在学习过程中经常看见各种渐变窗体.作为几乎没做过美工的程序员,我对各种颜色的argb值不熟,颜色的英文单词也只认识部分.为了不至于每次都用Colors点出颜色再随机挑选 ...

  7. java查看程序执行时间

    public static void main(String[] args) { long a= System.currentTimeMillis();//获取当前系统时间(毫秒) for (int ...

  8. Java面试题积累

    持续积累中... 1.Java支持的数据类型有哪些?什么是自动拆装箱? 数据类型分为两大种,基本类型和引用类型. 基本类型有8种:byte short int long char float doub ...

  9. Windows环境下使用python 3.x自带的CGI服务器测试cgi脚本--Python

    1.在桌面上新建一个文件夹作为服务器目录文件夹(文件夹名称自定义,文件夹位置自定义),在www文件下再建一个文件夹,文件夹名为“cgi-bin”,须是这个文件名,其他试过不行(原因暂时未知)

  10. BZOJ 1079: [SCOI2008]着色方案(巧妙的dp)

    BZOJ 1079: [SCOI2008]着色方案(巧妙的dp) 题意:有\(n\)个木块排成一行,从左到右依次编号为\(1\)~\(n\).你有\(k\)种颜色的油漆,其中第\(i\)种颜色的油漆足 ...