1 条题解
-
0
题意分析
本题要求在给定的m×n的0-1矩阵中,找出元素全为1的最大子矩阵,并输出其元素个数。子矩阵的定义是连续的行和连续的列组成的矩阵,最大指的是元素数量最多。如果矩阵全为0,则输出0。
解题思路
核心方法:单调栈优化的直方图最大面积算法
该问题可转化为“直方图最大面积”问题的扩展:
- 行压缩处理:将每一行视为直方图的基底,计算每一列从当前行向上连续1的高度。
- 直方图最大面积:对于每一行的高度数组,使用单调栈快速计算以当前行为底的最大矩形面积。
- 全局最大值:遍历所有行,取各直方图最大面积的最大值作为最终结果。
算法步骤
- 行压缩:对于每一行,计算每个位置(i,j)向上连续1的高度
h[j]
,若当前位置为0则高度重置为0。 - 单调栈计算:使用单调递增栈维护高度数组的索引,栈中元素对应的高度递增。
- 当遇到比栈顶高度小的元素时,弹出栈顶元素计算以该高度为高的矩形面积。
- 面积公式:
(当前列 - 弹出后栈顶列) × 弹出高度
。
- 更新最大值:遍历所有行的直方图最大面积,取最大值作为结果。
###标程
#include<stdio.h> #include<string.h> #include<iostream> #include<stack> using namespace std; int main() { int i, j, m, n, x, top, tmp, ans, h[2020], a[2020]; stack<int> st; // 单调栈,存储列索引,对应高度递增 while (~scanf("%d%d", &m, &n)) { ans = 0; memset(h, 0, sizeof(h)); // 初始化高度数组(处理第一行) for (i = 0; i < m; i++) { // 遍历每一行 for (j = 1; j <= n; j++) { // j从1开始便于后续处理 scanf("%d", &x); if (x == 1) h[j] = h[j] + 1; // 连续1的高度累加 else h[j] = 0; // 遇到0,高度重置为0 a[j] = h[j]; // a数组用于单调栈计算 } a[n+1] = -1; // 末尾设为-1,确保栈中元素全部出栈 for (j = 1; j <= n + 1; j++) { if (st.empty() || a[j] >= a[st.top()]) { st.push(j); // 栈空或当前高度≥栈顶,直接入栈 } else { while (!st.empty() && a[j] < a[st.top()]) { top = st.top(); st.pop(); tmp = (j - top) * a[top]; // 计算面积 if (tmp > ans) ans = tmp; // 更新最大面积 } st.push(top); // 延伸最后弹出的索引 a[top] = a[j]; // 修改高度为当前高度 } } while (!st.empty()) st.pop(); // 清空栈,处理下一行 } printf("%d\n", ans); } return 0; }
关键步骤说明
-
行压缩处理:
h[j]
表示第j列从当前行向上连续1的高度。例如,对于矩阵:0 1 1 0 0 1 1 0
第一行的
h
为[0,1,1,0]
,第二行的h
为[0,2,2,0]
。 -
单调栈原理:
- 栈中存储列索引,对应高度递增。例如,高度数组
[2,2,0]
的处理过程:- 入栈1(h=2)、2(h=2)
- 遇到j=3(h=0),弹出栈顶2,计算面积
(3-2)*2=2
;弹出栈顶1,计算面积(3-1)*2=4
- 入栈1(h=0)
- 面积计算逻辑:以弹出高度为高,宽度为当前列与弹出后栈顶列的差。
- 栈中存储列索引,对应高度递增。例如,高度数组
-
边界处理:
a[n+1]=-1
确保处理完所有列后栈中元素全部出栈,计算剩余高度的面积。- 初始化
h
数组为0,正确处理第一行的高度计算。
算法正确性证明
- 行压缩的有效性:将二维问题转化为一维直方图问题,每一行的高度数组正确反映了上方连续1的情况。
- 单调栈的高效性:每个元素入栈和出栈各一次,时间复杂度O(n),总时间复杂度为O(mn),适用于m,n≤2000的规模。
- 最大面积的正确性:对于每个可能的矩形,其高度由某一行的连续1高度决定,宽度由左右边界决定,单调栈确保找到所有可能的矩形。
示例解析
以输入数据的第二个测试用例为例:
4 4 0 0 0 0 0 1 1 0 0 1 1 0 0 0 0 0
- 各行的高度数组h:
- 行0:[0,0,0,0]
- 行1:[0,1,1,0]
- 行2:[0,2,2,0]
- 行3:[0,0,0,0]
- 处理行2的h=[0,2,2,0]:
- a数组为[0,2,2,0,-1](末尾加-1)
- 单调栈处理:
- j=1(a=0)入栈
- j=2(a=2≥0)入栈
- j=3(a=2≥2)入栈
- j=4(a=0<2):弹出j=3,面积
(4-3)*2=2
;弹出j=2,面积(4-2)*2=4
;入栈2(a=0) - j=5(a=-1<0):弹出j=2,面积
(5-1)*0=0
- 最大面积为4,对应2×2的全1子矩阵。
复杂度分析
- 时间复杂度:O(mn),其中m为行数,n为列数。每行处理时间O(n),总时间O(mn)。
- 空间复杂度:O(n),用于存储高度数组和单调栈。
总结
该算法通过行压缩和单调栈优化,高效解决了二维0-1矩阵的最大全1子矩阵问题。核心在于将二维问题转化为一维直方图问题,并利用单调栈快速计算每个直方图的最大面积,最终得到全局最大值。
- 1
信息
- ID
- 2495
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者