1. 程式人生 > >棧_單調棧_POJ2559_Largest Rectangle in a Histogram

棧_單調棧_POJ2559_Largest Rectangle in a Histogram

思路分析:

    本題是單調棧的典型應用, 下面先給出AC程式碼然後證明程式的正確性和分析其時間複雜度.

//POJ2559_Largest Rectangle in a Histogram
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
const int MAXN = 1e5 + 5;
int re[MAXN], n;
int main(){
	while(scanf("%d", &n), n){
		for(int i = 1; i <= n; ++i) scanf("%d", &re[i]); re[n + 1] = 0;
		vector<pair<int, int> > ve;//first:高度, second;寬度
		long long res = 0;
		ve.push_back(make_pair(re[1], 1));
		for(int i = 2; i <= n + 1; ++i){
			int width = 0;
			while(!ve.empty() && ve.back().first >= re[i]) 
				width += ve.back().second
				, res = max(res, (long long)ve.back().first * width), ve.pop_back();
			ve.push_back(make_pair(re[i], width + 1));
		}
		cout << res << endl;
	}	
	return 0;
} 

對於上述程式的正確性證明:

    設當前考察的是最左邊的第i個矩形, 那麼由原圖形中前i個矩形構成的區域的最大矩形子段的面積為 max{ 棧ve中儲存的矩形構成的區域的矩形子段面積最大值, res }, 且棧ve中儲存的矩形從棧底到棧頂(對應從左到右)矩形高度嚴格單調遞增(如下圖的CA和MN之間所有矩形), 因此棧中矩形構成的區域的最大矩形子段的最左邊的的高必定為ve中某個矩形左邊的高(如CA或EF), 且其右邊的高為ve中最後一個矩形右邊(邊MN)的一部分, 可以證明在每次第15行迴圈頭檢測之前該結論均成立, 因此結論正確

                                   

時間複雜度分析:

    由於每次執行第17至19行的迴圈體均從ve中彈出1個元素(矩形), 對於ve, 僅在第14行和第18行的語句向其加入元素, 因此有n + 1個元素加入ve, 故第17至19行的迴圈體執行次數為O(n)次, 因此上述程式的時間複雜度為O(n)