NJU-高级算法-子矩阵问题

子矩阵问题

本文参考算法题:直方图和0-1矩阵中最大矩形

原作者飞翔的蓝鲸

Description

给定一个矩形区域,每一个位置上都是1或0,求该矩阵中每一个位置上都是1的最大子矩形区域中的1的个数。

Input

输入第一行为测试用例个数。每一个用例有若干行,第一行为矩阵行数n和列数m,下面的n行每一行是用空格隔开的0或1。

Output

输出一个数值。

Sample Input 1

1
3 4
1 0 1 1
1 1 1 1
1 1 1 0

Sample Output 1

6

 

思路

思路看的论坛飞翔的蓝鲸大神的,原文非常清晰。

本题中可以将矩阵转化为记录从上往下将矩阵逐行作为底层往上算每个位置连续为1的个数

1 0 1 1  ---  1 0 1 1          
1 1 1 1  ---  2 1 2 2
1 1 1 0  ---  3 2 3 0

这样可以将转化后的矩阵每一行看作一个直方图

例如,对于第二行:3 2 3 0

NJU-高级算法-子矩阵问题_第1张图片

 

代码

#include 
#include 
#include 
using namespace std;

int a[99][99] = { 0 };

int main()
{
	int t, n, m;
	scanf("%d", &t);
	for (int turn = 0; turn < t; turn++) {
		scanf("%d%d", &n, &m);
		fill(a[0], a[0] + n * m, 5);
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				scanf("%d", &a[i][j]);
			}
		}

		//从第二行开始将每一行中为1的元素改为从该位置往上连续1的个数
		for (int i = 1; i < n; i++) {
			for (int j = 0; j < m; j++) {
				if (a[i][j] == 1 && a[i - 1][j] != 0) {//只向上算连续的1的个数
					a[i][j] += a[i - 1][j];
				}
			}
		}


		int res = 0;//res为最终结果
        //遍历矩阵每行算各行的符合条件的最大子矩阵,然后取各行结果maxTemp最大的为最终结果res
		for (int i = 0; i < n; i++) {
			stack s;
			int j = 1, maxTemp = a[i][0];
			s.push(0);

			while (j=栈顶元素)时,
                //将当前元素(矩阵该行的元素下标,如a[i][j],就将j入栈)入栈
				if (j != m && (s.empty() || a[i][j] >= a[i][s.top()])) {
					s.push(j);
					j++;
				}
                //否则记录下栈顶元素对应在矩阵中的值topNum,并弹出栈顶元素
                //若当前栈不空,则当前弹出元素对应的最大子矩阵1的个数为topNum*(j-s.top()-1)
                //若当前栈空了,则说明弹出的元素为最小元素,其对应最大子矩阵1个数就是topNum*j
                //然后更新一下当前行的最大子矩阵1的个数maxTemp值
				else {
					int topNum = a[i][s.top()];
					s.pop();
					int currMax = !s.empty() ? topNum * (j - s.top() - 1) : topNum * j;
					maxTemp = max(currMax, maxTemp);
				}
			}
			res = max(maxTemp, res);
		}
		if (turn + 1 == t) {
			printf("%d", res);
		}
		else {
			printf("%d\n", res);
		}
	}
	return 0;
}

 

你可能感兴趣的:(NJU-高级算法)