程序员面试金典——解题总结: 9.18高难度题 18.12给定一个正整数和负整数组成的N*M矩阵,编写代码找出元素总和最大的子矩阵。

#include 
#include 

using namespace std;
/*
问题:给定一个正整数和负整数组成的N*M矩阵,编写代码找出元素总和最大的子矩阵。
分析:暴力破解:遍历所有子矩阵耗时O(N^4),对每个子矩阵求和耗时O(N^2),总共耗时O(N^6)
      动态规划:可以使得对子矩阵求和的时间复杂度降至O(1)。
	    |A B|  假设左边为矩阵,那么area(D) = ValD - ValB - ValC + ValA
		|C D|
	  时间为O(N^3)的解法:在一维中,最大子序列和可以通过O(N)的动态规划算法求出,而每个子矩阵可以表示未一组连续的行和一组连续的列。
	                      迭代所有连续行的组合,对每一种组合找出一组可以给出元素总和最大的列。
						  这里的话假设知道行的起始位置和结束位置,可以将行起始位位置和结束位置所在的一列看成一个数字,不断枚举起始列,即可

输入: 
2 3(行和列) 
1 -2 3 
-4 5 6 

3 5
9 -8 1 3 -2
-3 7 6 -2 4
6 -4 -4 8 -7
输出: 
12
-2 3
5 6

19
9 -8 1 3
-3 7 6 -2
6 -4 -4 8
关键:
1 	  时间为O(N^3)的解法:在一维中,最大子序列和可以通过O(N)的动态规划算法求出,而每个子矩阵可以表示未一组连续的行和一组连续的列。
	                      迭代所有连续行的组合,对每一种组合找出一组可以给出元素总和最大的列。
						  这里的话假设知道行的起始位置和结束位置,可以将行起始位位置和结束位置所在的一列看成一个数字,不断枚举起始列,即可
2 
	for(int rowBegin = 0 ; rowBegin < row ; rowBegin++)
	{
		for(int rowEnd = rowBegin ; rowEnd < row; rowEnd++)
		{
			int start = getSum(rowBegin , rowEnd , 0 , matrix);
			int columnMax = start;//记录在起止行确定的情况下,多个列的最大值
			int colBegin = 0;
			int colEnd = 0;
			//枚举所有的列
			for(int i = 1 ; i < column ; i++)
			{
				//统计起止行所在列的元素总和
				if(start < 0)
				{
					start = getSum(rowBegin , rowEnd , i , matrix);
					colBegin = colEnd = i;
				}
				else
				{
					start += getSum(rowBegin , rowEnd , i , matrix);
					colEnd = i;
				}
				if(start > columnMax)
				{
					columnMax = start;
				}
				if(columnMax > max )
				{
					max = columnMax;
					//需要行的位置
					maxRowBegin = rowBegin;
					maxRowEnd = rowEnd;
					//记录列的起止位置,如果放在列计算最大值的时候更新,会有错误
					maxColBegin = colBegin;
					maxColEnd = colEnd;
				}
			}
		}
	}
*/

const int MAXSIZE = 100;

int getSum(int rowBegin , int rowEnd , int column , int matrix[][MAXSIZE])
{
	int result = 0;
	if(NULL == matrix || rowEnd < rowBegin || column < 0 || rowBegin < 0)
	{
		return result;
	}
	for(int i = rowBegin ; i <= rowEnd ; i++)
	{
		result += matrix[i][column];
	}
	return result;
}

//存储最大子矩阵结果:包含最大和,行的起始和结束位置,列的起始和结束位置
class Result
{
public:
	Result(){}
	int _result;
	int _rowBegin;
	int _rowEnd;
	int _colBegin;
	int _colEnd;
};

Result findMaxSumMatrix(int row , int column , int matrix[][MAXSIZE])
{
	int max = INT_MIN;
	int maxRowBegin = 0 ; 
	int maxRowEnd = 0;
	int maxColBegin = 0;
	int maxColEnd = 0;
	for(int rowBegin = 0 ; rowBegin < row ; rowBegin++)
	{
		for(int rowEnd = rowBegin ; rowEnd < row; rowEnd++)
		{
			int start = getSum(rowBegin , rowEnd , 0 , matrix);
			int columnMax = start;//记录在起止行确定的情况下,多个列的最大值
			int colBegin = 0;
			int colEnd = 0;
			//枚举所有的列
			for(int i = 1 ; i < column ; i++)
			{
				//统计起止行所在列的元素总和
				if(start < 0)
				{
					start = getSum(rowBegin , rowEnd , i , matrix);
					colBegin = colEnd = i;
				}
				else
				{
					start += getSum(rowBegin , rowEnd , i , matrix);
					colEnd = i;
				}
				if(start > columnMax)
				{
					columnMax = start;
				}
				if(columnMax > max )
				{
					max = columnMax;
					//需要行的位置
					maxRowBegin = rowBegin;
					maxRowEnd = rowEnd;
					//记录列的起止位置,如果放在列计算最大值的时候更新,会有错误
					maxColBegin = colBegin;
					maxColEnd = colEnd;
				}
			}
		}
	}
	Result result;
	result._result = max;
	result._rowBegin = maxRowBegin;
	result._rowEnd = maxRowEnd;
	result._colBegin = maxColBegin;
	result._colEnd = maxColEnd;
	return result;
}

void print(Result& result , int matrix[][MAXSIZE])
{
	cout << result._result << endl;
	for(int i = result._rowBegin ; i <= result._rowEnd ; i++ )
	{
		for(int j = result._colBegin ; j <= result._colEnd ; j++)
		{
			cout << matrix[i][j] << " ";
		}
		cout << endl;
	}
}

void process()
{
	int row;
	int column;
	int gMatrix[MAXSIZE][MAXSIZE];
	while(cin >> row >> column)
	{
		if(row > MAXSIZE || column > MAXSIZE)
		{
			cout << "row >" << MAXSIZE << ", or column >" << MAXSIZE;
			continue;
		}
		memset(gMatrix , 0 , sizeof(gMatrix));
		for(int i = 0 ; i < row ; i++ )
		{
			for(int j = 0 ; j < column ; j++)
			{
				cin >> gMatrix[i][j];
			}
		}
		Result result = findMaxSumMatrix(row , column , gMatrix);
		print(result , gMatrix);
	}
}

int main(int argc , char* argv[])
{
	process();
	getchar();
	return 0;
}

你可能感兴趣的:(程序员面试金典)