描述

计算矩阵中,最大和的子矩阵,并输出最大的和

测试用例

用例一:

$$\begin{equation} \begin{bmatrix*}[c] -3 & -5 & -1 & 5 \newline 2 & -4 & -2 & 4 \newline -1 & 3 & -1 & 3 \end{bmatrix*} \end{equation}$$

用例二:

$$\begin{equation} \begin{bmatrix*}[c] -3 & -5 & -1 & 5 \newline 9 & -4 & -2 & 4 \newline -1 & 3 & -1 & 3 \end{bmatrix*} \end{equation}$$

用例三:

$$\begin{equation} \begin{bmatrix*}[c] -3 & -5 & -1 & 5 \newline 7 & -4 & -2 & 4 \newline -1 & 3 & -1 & 3 \end{bmatrix*} \end{equation}$$

用例四:

$$\begin{equation} \begin{bmatrix*}[c] -3 & -5 & -1 & 5 \newline 9 & -4 & -2 & 4 \newline -1 & -2 & -1 & -3 \end{bmatrix*} \end{equation}$$

用例五:

$$\begin{equation} \begin{bmatrix*}[c] -3 & -5 & -1 & 5 \newline 9 & -4 & -3 & 4 \newline -1 & -2 & -1 & -3 \end{bmatrix*} \end{equation}$$

用例六:

$$\begin{equation} \begin{bmatrix*}[c] -3 & -5 & -1 & 5 \newline 9 & 1 & -7 & 4 \newline -1 & -2 & -1 & -3 \end{bmatrix*} \end{equation}$$

用例七:

$$\begin{equation} \begin{bmatrix*}[c] -3 & 5 & -1 & -5 \newline 9 & 4 & -7 & -4 \newline -1 & 3 & -1 & -3 \end{bmatrix*} \end{equation}$$

用例八:

$$\begin{equation} \begin{bmatrix*}[c] -3 & 2 & -1 & 2 \newline 5 & 4 & -2 & 0 \newline -1 & 3 & -1 & 2 \end{bmatrix*} \end{equation}$$

用例九:

$$\begin{equation} \begin{bmatrix*}[c] -3 & 5 & -1 & -5 \newline 2 & 4 & -2 & -4 \newline -1 & 3 & -1 & -3 \end{bmatrix*} \end{equation}$$

用例十:

$$\begin{equation} \begin{bmatrix*}[c] -3 & 3 & -1 & -5 \newline 9 & -4 & -7 & -4 \newline -1 & 3 & -1 & -3 \end{bmatrix*} \end{equation}$$

测试用例十一:

$$\begin{equation} \begin{bmatrix*}[c] 1 & 2 & 3 & 4 \newline 5 & 6 & 7 & 8 \newline 9 & 10 & 11 & 12 \end{bmatrix*} \end{equation}$$

测试用例十二:

$$\begin{equation} \begin{bmatrix*}[c] -1 & -2 & -3 & -4 \newline -5 & -6 & -7 & -8 \newline -9 & -10 & -11 & -12 \end{bmatrix*} \end{equation}$$

测试用例十三:

$$\begin{equation} \begin{bmatrix*}[c] -12 & -11 & -10 & -9 \newline -8 & -7 & -6 & -5 \newline -4 & -3 & -2 & -1 \end{bmatrix*} \end{equation}$$

方法一:暴力算法

void testMatMaxSum() {
	/*int arr[][4] = {
		{-3, -5, -1, 5},
		{2, -4, -2, 4},
		{-1, 3, -1, 3}
	};*/
	/*int arr[][4] = {
		{-3, -5, -1, 5},
		{9, -4, -2, 4},
		{-1, 3, -1, 3}
	};*/
	/*int arr[][4] = {
		{-3, -5, -1, 5},
		{7, -4, -2, 4},
		{-1, 3, -1, 3}
	};*/
	/*int arr[][4] = {
		{-3, -5, -1, 5},
		{9, -4, -2, 4},
		{-1, -2, -1, -3}
	};*/
	/*int arr[][4] = {
		{-3, -5, -1, 5},
		{9, 1, -3, 4},
		{-1, -2, -1, -3}
	};*/
	/*int arr[][4] = {
		{-3, -5, -1, 5},
		{9, 1, -7, 4},
		{-1, -2, -1, -3}
	};*/
	/*int arr[][4] = {
		{-3, 5, -1, -5},
		{9, 4, -7, -4},
		{-1, 3, -1, -3}
	};*/
	/*int arr[][4] = {
		{-3, 2, -1, 2},
		{5, 4, -2, 0},
		{-1, 3, -1, 2}
	};*/
	/*int arr[][4] = {
		{-3, 5, -1, 5},
		{2, 4, -2, 4},
		{-1, 3, -1, 3}
	};*/
	/*int arr[][4] = {
		{-3, 3, -1, -5},
		{9, -4, -7, -4},
		{-1, 3, -1, -3}
	};*/
	/*int arr[3][4]{ 0 };
	int n = 1;
	for (int i = 0; i < 3; ++i)
	{
		for (int j = 0; j < 4; ++j) {
			arr[i][j] = n++;
		}
	}*/
	int arr[3][4]{0};
	int n = -12;
	for (int i = 0; i < 3; ++i)
	{
		for (int j = 0; j < 4; ++j) {
			arr[i][j] = n++;
		}
	}

	int dp[4][5]{ 0 };
	for (int i = 1; i < 4; ++i)
	{
		for (int j = 1; j < 5; ++j)
		{
			dp[i][j] = arr[i - 1][j - 1];
		}
	}

	for (int i = 1; i < 4; ++i)
	{
		for (int j = 1; j < 5; ++j)
		{
			dp[i][j] += dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1];
		}
	}
	
	int start_x = 1, start_y = 1, end_x = 1, end_y = 1;
	int max_sum = dp[start_x][start_y];
	for (int x = 0; x < 3; x++)
	{
		for (int y = 0; y < 4; y++)
		{
			for (int i = 1; i < 4-x; i++)
			{
				for (int j = 1; j < 5-y; j++)
				{
					int b = i + x;
					int r = j + y;
					int cur_sum = dp[b][r] - dp[b][j - 1] - dp[i - 1][r] + dp[i - 1][j - 1];
					if (max_sum < cur_sum)
					{
						max_sum = cur_sum;
						start_x = i;
						start_y = j;
						end_x = b;
						end_y = r;
					}
				}
			}
		}
	}

	cout << "max: " << max_sum << endl;
	cout << "左上:[" << (start_x - 1) << ", " << (start_y - 1) << "] 右下:[" << (end_x - 1) << ", " << (end_y - 1) << "]" << endl;
}

方法二:模拟人的思维方式

此方法要考虑的情况较多

void testMatMaxSum() {
	/*int arr[][4] = {
		{-3, -5, -1, 5},
		{2, -4, -2, 4},
		{-1, 3, -1, 3}
	};*/
	/*int arr[][4] = {
		{-3, -5, -1, 5},
		{9, -4, -2, 4},
		{-1, 3, -1, 3}
	};*/
	/*int arr[][4] = {
		{-3, -5, -1, 5},
		{7, -4, -2, 4},
		{-1, 3, -1, 3}
	};*/
	/*int arr[][4] = {
		{-3, -5, -1, 5},
		{9, -4, -2, 4},
		{-1, -2, -1, -3}
	};*/
	/*int arr[][4] = {
		{-3, -5, -1, 5},
		{9, 1, -3, 4},
		{-1, -2, -1, -3}
	};*/
	/*int arr[][4] = {
		{-3, -5, -1, 5},
		{9, 1, -7, 4},
		{-1, -2, -1, -3}
	};*/
	/*int arr[][4] = {
		{-3, 5, -1, -5},
		{9, 4, -7, -4},
		{-1, 3, -1, -3}
	};*/
	/*int arr[][4] = {
		{-3, 2, -1, 2},
		{5, 4, -2, 0},
		{-1, 3, -1, 2}
	};*/
	/*int arr[][4] = {
		{-3, 5, -1, 5},
		{2, 4, -2, 4},
		{-1, 3, -1, 3}
	};*/
	int arr[][4] = {
		{-3, 3, -1, -5},
		{9, -4, -7, -4},
		{-1, 3, -1, -3}
	};
	/*int arr[3][4]{ 0 };
	int n = 1;
	for (int i = 0; i < 3; ++i)
	{
		for (int j = 0; j < 4; ++j) {
			arr[i][j] = n++;
		}
	}*/
	/*int arr[3][4]{0};
	int n = -12;
	for (int i = 0; i < 3; ++i)
	{
		for (int j = 0; j < 4; ++j) {
			arr[i][j] = n++;
		}
	}*/
	int dp[4][5]{ 0 };
	for (int i = 1; i < 4; ++i)
	{
		for (int j = 1; j < 5; ++j)
		{
			dp[i][j] = arr[i - 1][j - 1];
		}
	}

	for (int i = 1; i < 4; ++i)
	{
		for (int j = 1; j < 5; ++j)
		{
			dp[i][j] += dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1];
		}
	}

	int dp_max = arr[0][0], real_dp_max = dp_max;
	int t = 1, l = 1, b = 1, r = 1;
	for (int i = 1; i < 4; ++i)
	{
		int cur_t = 1, cur_l = 1, cur_b = 1, cur_r = 1;
		for (int j = 1; j < 5; ++j)
		{
			// 根据矩阵元素的和的 dp 移动矩阵临时的左上角坐标和右下角坐标
			if (dp_max < dp[i][j])
			{
				dp_max = dp[i][j];
				cur_b = i;
				cur_r = j;
			}
			if (cur_t != 1 || cur_l != 1)
			{
				int cur_real_dp_max = dp[i][j] - dp[i][cur_l - 1] - dp[cur_t - 1][j] + dp[cur_t - 1][cur_l - 1];

				if (dp_max < cur_real_dp_max) {
					dp_max = cur_real_dp_max;
					cur_b = i;
					cur_r = j;
				}
			}
			if (dp_max < arr[i - 1][j - 1])
			{
				dp_max = arr[i - 1][j - 1];
				cur_t = i;
				cur_l = j;
				cur_b = i;
				cur_r = j;
			}
			// 判断是否需要改变最终矩阵的左上角和右下角坐标
			// 如果矩阵的左上角坐标发生过变化,则需要与真实的矩阵最大和进行比较
			if ((t != 1 || l != 1) && dp_max > real_dp_max)
			{
				int max_t = cur_t > t ? cur_t : t;
				int max_l = cur_l > l ? cur_l : l;
				// 分别计算 (t,l)-(max_t,max_l) 矩阵的和
				// (cur_t,cur_l)-(max_t,max_l) 矩阵的和
				// 只有当后者大于前者时才需更新矩阵的左上角坐标
				int max_sum = dp[max_t][max_l] - dp[max_t][l - 1] - dp[t - 1][max_l] + dp[t - 1][l - 1];
				int new_sum = dp[max_t][max_l] - dp[max_t][cur_l - 1] - dp[cur_t - 1][max_l] + dp[cur_t - 1][cur_l - 1];
				
				if (max_sum < new_sum)
				{
					max_sum = new_sum;
					t = cur_t;
					l = cur_l;
				}
				if (real_dp_max < max_sum)
				{
					b = max_t;
					r = max_l;
					real_dp_max = max_sum;
				}
			}
			if (i >= t && j >= l)
			{
				int cur_real_dp_max = dp[i][j] - dp[i][l - 1] - dp[t - 1][j] + dp[t - 1][l - 1];
				if (real_dp_max < cur_real_dp_max)
				{
					b = i;
					r = j;
					real_dp_max = cur_real_dp_max;
				}
			}
			if (real_dp_max < dp_max)
			{
				real_dp_max = dp_max;
				t = cur_t;
				l = cur_l;
				b = cur_b;
				r = cur_r;
			}
		}
	}

	cout << "max: " << real_dp_max << endl;
	cout << "左上:[" << (t - 1) << ", " << (l - 1) << "] 右下:[" << (b - 1) << ", " << (r - 1) << "]" << endl;
}