UVa514_Rails
题意
给定编号为1~n的车厢入栈,判断它们能否按照一定的顺序出栈。
如给定n=5,那么出栈顺序54123是不可能的。
思路
使用栈模拟即可。
设置con变量,初值为0,表示入栈时下一节车厢的编号。
遍历给定的出栈顺序,假设当前的编号是v,如果v>=con说明需要把con到v的车厢入栈,这样栈顶就是v,可以取出。如果v<con,说明v已经入栈了,而且只能在栈顶,如果不在栈顶则说明这种顺序是不可实现的。
解决
1 |
|
UVa442_Matrix Chain Multiplication
题意
输入n个矩阵的维度和一些矩阵乘法表达式,输出需要计算乘法的次数。如果乘法无法进行,则输出error。
如A是50*
10的矩阵而B是10*
20的,C是20*
5的,那么(A(BC))的乘法次数为10*
20*
5(BC的乘法次数) + 50*
10*
5(A(BC)的乘法次数)=3500
分析
类似于使用栈来计算表达式,只不过计算的过程需要根据具体的矩阵行列数来得出。并且,一旦检测到矩阵的计算非法,应该立刻停止计算并输出error。
解决
1 |
|
HDU4699_Editor
描述
模拟一个编辑器,有五种操作:
1 插入,即在光标后面插入一个数
2 删除,如果光标前面不空,删除光标前面的数
3 光标左移
4 光标右移
5 给出参数k,查询前i个数中最大的前缀和并输出这个前缀和,要求i <= k
数据范围
操作数量 1 < n < 1e6
查询参数 1 <= k <= cur(cur是光标)
编辑器输入的都是数字,范围-1000 < ai < 1000
思路
使用两个栈来存储光标左边和右边的数字。
再用两个数组分别存储光标之前所有位置的前缀和,最大前缀和的值。
使用一个辅助变量来记录光标。
模拟即可。
注意左右移动,删除时一定要保证栈不空。
解决
1 |
|
POJ2559_Largest Rectangle in a Histogram
题意
一个直方图由一系列宽度为1,高度不等的矩形组成,下图就是一个直方图:
我们假设这个直方图的每个矩形高度分别为2 1 4 5 1 3 3,那么该图中的最大矩形的面积是8,如下图:
现在给出直方图的一串矩形高度,求出其最大矩形
数据范围
矩形数量 1 < n < 100000
思路
我们怎样找到最大的矩形呢?我们知道矩形的面积在这里是宽度乘以高度。为了让矩形尽可能地大,我们显然需要取已经存在的高度作为最终矩形的高度。
那么,假设我们取第i个矩形的高度hi作为最终最大矩形的高度,我们知道,在高度一定的前提下,我们应该尽量扩展矩形的宽度,因此,我们从第i个小矩形开始向两边扩展,如果旁边的矩形高度不小于hi,我们可以把它并入最终矩形,但如果旁边矩形的高度一旦小于hi,我们的扩展也就到头了。
换句话说,我们可以选定第i个矩形为基准,向左向右分别寻找到第一个高度小于hi的矩形,记录这两个矩形之间的宽度作为最终矩形的宽度,答案一定在这些矩形之中。
但很遗憾,朴素的遍历方法的复杂度是O(n²),显然超过了本题的承受范围。
单调栈
假设我们有一个栈s,我们周而复始地对它做下面的操作:
1 读入下一个矩形的高度hi
2 判断hi和栈顶元素的大小,如果hi大于栈顶元素,执行3,否则执行4
3 hi入栈
4 一直弹栈直到栈里没有比hi更大的元素为止,之后执行3
我们成这样的数据结构为单调栈,因为经过这样的操作,可以保证栈内部的元素是单调的。
我们如何应用单调栈来优化上面的解题策略呢?
我们设置一个数组w来存储每个元素可以扩展的最大宽度,对于每次新元素入栈,我们知道由于栈是递增的,此时还在栈中的元素都可以向后扩展一个单位。而仅仅排在新元素前面却不在栈中的元素,由于其后方必定有比它小的元素阻碍它的扩展(不然怎么会被弹出栈呢)所以不会受到影响。
所以每次新元素入栈时,我们把栈中的每个元素的w值加一。
而对于w的初始化,新元素入栈之前,我们从栈中找到第一个比新元素小的元素下标,把w初始化为两个下标之差即可。
为了进一步优化,可以把新元素入栈时对栈内元素的操作累加起来,在栈内元素被挤出去的时候完成,具体做法是当栈内元素弹栈时,其w值加上新元素和它自己的下标差。
解决
1 |
|