单调栈讲解
以前一直有接觸,但是一直沒單獨進行分析處理
單調棧:維護其中元素單調性的棧
也就是從棧底到棧頂都是有序的
維護:如果入棧的元素滿足單調性,直接入棧;如果不滿足,就讓棧頂元素出棧,直到能讓入棧元素滿足單調性為止,再將元素入棧
(已經出棧的元素就被拋棄)
例題:
求直方圖中包含的最大矩陣面積
題解鏈接
單調棧問題
我們可以用一個單調棧來維護每個矩陣的高度和寬度,
當前矩陣高于棧頂,進棧
當前矩陣a小于棧頂時,直到棧為空或者棧頂矩形的高度比當前矩形小。在出棧過程中,我們累計被彈出的矩形的寬度和。每彈出一個矩形,就用他的高度(他指被彈出的矩陣)乘上累計的寬度取更新答案,因為每次彈出的高度要比上次彈出的小,相當于依次求以從左往右以每個矩陣高的面積(如圖所示)。整個出棧過程結束后,我們把一個高度為當前矩陣高度,寬度為累計值的新矩陣入棧。
全部掃描過后,我們要將棧內剩余矩陣依次彈出,并利用相同的方法更新答案。
最大全 1 矩陣
給一個01矩陣,問最大的全1矩陣是多少?
題解:
先預處理,求出每一行位置上連續的最大的1的矩陣的
高度是多少,再對每一行進行一個單調棧處理即可
代碼:
STL的stack版
typedef pair<int, int>pa;int n, m; int a[2005][2005]; pa f[2005]; stack<pa>s;int main() {while(~scanf("%d%d", &n, &m)){for(int i = 1; i <= n; i++){for(int j = 1; j <= m; j++){scanf("%d", &a[i][j]);if (a[i][j]) a[i][j] += a[i-1][j];//求連續的高度 }}int ans = 0;pa v;for(int i = 1; i <= n; i++){for(int j = 1; j <= m; j++){if (s.empty() && !a[i][j]) continue;if (s.empty() || s.top().second <= a[i][j])//當高度小于時 s.push(make_pair(j, a[i][j]));else {while(!s.empty() && s.top().second > a[i][j]){v = s.top();s.pop();int area = (j-v.first)*v.second;//求面積 if (area > ans) ans = area; }s.push(make_pair(v.first, a[i][j]));}}}printf("%d\n", ans);}return 0; }手寫stack版
for(int i=1;i<=n;i++){top=0;//每一行清空棧 for(int j=1;j<=m+1;j++){if(top==0||ri[i][j]>=ri[i][st[top]]){st[++top]=j;}else { int id; while(top!=0&&ri[i][j]<ri[i][st[top]]){id=st[top];top--;int w=min(j-id,ri[i][id]);ans=max(ans,w*w);ans2=max(ans2,(j-id)*ri[i][id]);}st[++top]=id;//將最后一次出棧的棧頂元素延申并入棧ri[i][id]=ri[i][j]; }}}ACM-ICPC 2018 南京賽區網絡預賽 B-The writing on the wal
給你一個n * m(1e5 * 100)的矩陣和k(1e5)個黑點,黑點會給定坐標,問有多少個不含這些黑點的子矩形。
參考代碼
這個講的巨詳細
題解:
相當于每次從一個矩陣的最右下角開始加一個一列的矩陣,加一個兩列的矩陣,加一個三列的矩陣…
總結
- 上一篇: VR产业及产品 2020-12
- 下一篇: HDOJ树形DP专题之Centroid