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

 

代碼

#include <iostream>
#include <algorithm>
#include <stack>
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<int> s;
			int j = 1, maxTemp = a[i][0];
			s.push(0);

			while (j<m || j==m && !s.empty()) {
                //未將矩陣當前行所有元素入棧且(棧爲空或當前遍歷元素>=棧頂元素)時,
                //將當前元素(矩陣該行的元素下標,如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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章