homework-10

既然是为了宣传...那么还是把讲解部分放在前面吧...

借用适牛的一句话:没有人敢说自己精通动态规划。

所以我也就着这道题稍微说说我对动态规划的理解吧...

动态规划的基本思想就是空间换时间,就是申请更多的内存空间存储中间环节以减少重复计算。

回到这道题,我们先看较为简单的一维问题:求数列的最大子数列。

是不是很容易想到枚举前后端点?

O(n^3)的时间复杂度可吃不消啊...

于是我们就要想,如何才能存储下中间状态?

我们可以观察到,每次枚举出两个点时,循环求区间和是一个重复计算的过程,可以在上一步的基础上加上这一步多出来的点。

于是就要多申请一个变量空间记录这些累加和,但是时间复杂度因此下降到了O(n^2)。

这算是最基础的动态规划思想吧...

这道题O(n)的算法较难想,这就意味着我们要在线性时间内解决此问题。

需要搞清楚这样一个问题:我们假定从左向右枚举点,左端点就是数列的左端点,当枚举到一个点时,子数列和为负(假定可以找到非负整数解),那是不是就意味着这一段可以直接忽略?

我们假设从上述枚举到的右端点之后的所有点都是正数,则最大子数列必包含后面的所有点,若包含左侧的点,则数列和必小于不包含。

如果能够理解了,那其他处理也很简单,忽略这些点,将刚才右端点的下一位置为新的左端点,重新开始枚举,这就是O(n)的算法。

回到二维问题:求矩阵的最大子矩阵。

有了刚才一维的基础,二维问题也就简单多了。我们需要将二维转换为一维,这就需要对矩阵做按列的累加,中间过程存入新的数组。

我们只需用两个变量枚举此时矩阵的第i行到第j行,按列累加后生成的一维数列的最大子数列就是我们所求。

下面用.gif动图显示二维问题的解决过程:

谢谢观看!

1. 用户用你的程序读入一个数组文件 (就像我们以前做过的那样),显示初始状态 (就像围棋打谱程序那样)

1.1. 用户也可以自行定义数组的大小,或者要求随机生成一个数字矩阵。

于是这就是两种获取数字矩阵的方式,用户可以自定义行数&列数;也可以读入一个.txt文件。

其中,我设置了一个预处理,自动扫描目前数字矩阵的最大值,防止出现全负情况。

2. 用户这时候有两个选择

2.1  按 单步执行 键, 在 GUI 看到你的程序是如何一步一步算出目前最大子数组的范围,当前计算到的临时子数组是在哪里,等等。 最好用不同的颜色标识不同的状态。

2.2  按 自动运行 键, 在 GUI 看到程序自动运行,并自动显示过程, 每次改变状态的时候要稍作停留 (例如 1 秒钟的时间)

黄色底色代表目前扫描到的子矩阵,数字红色表示最大结果所在的子矩阵,旁边的maximum表示最大值。

可以点击"前进一步"或"自动进行"。

3. 咳,我没看清楚!  这时最好有一个 倒带 / 回滚 的键, 让用户可以看清楚关键的几步。

(当然,用户可以选择是普通模式还是扩展定义的连通模式)

可以点击"后退一步"。

抱歉括号里的内容没看到...写博客时候才注意...也就没做\v和\h...不过也并没有技术含量...

于是随手测了一组数据...目测是正确的...

代码请见GitHub

posted @ 2013-12-09 00:28  yiming.zou  阅读(261)  评论(0编辑  收藏  举报