感谢老师让我们不考试(然后继续练动态规划)
有个题目挺有意思的,在这里记录一下
【试题描述】
已知矩阵的大小定义为矩阵中所有元素的和。给定一个矩阵,你的任务是找到最大的非空(大小至少是11)子矩阵。
比如,如下44的矩阵
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
的最大子矩阵是:
9 2
-4 1
-1 8
这个子矩阵的大小是15。
【输入要求】
输入是一个N * N的矩阵。输入的第一行给出N (0 < N ≤ 100)。再后面的若干行中,依次(首先从左到右给出第一行的N个整数,再从左到右给出第二行的N个整数……)给出矩阵中的N2个整数,整数之间由空白字符分隔(空格或者空行)。已知矩阵中整数的范围都在[-127, 127]。
【输出要求】
输出最大子矩阵的大小。
这题的思路比我想的反而要简单,就是把每个子矩阵的值求出来找最大值
但问题在于怎样求每个子矩阵的和
这里用的思路是二维前缀和,先把第一行和第一列的前缀和都求出来,然后就可以把每一个子矩阵给求出来了,求法如下:
将其中一个子矩阵的左上角坐标表示为(i,j)右下角表示为(u,v),将每一处的前缀和记为s[a][b], 那么该子矩阵和就为 s[i][j] - s[u - 1][j] - s[i][v - 1] + s[u - 1][v - 1]
这个图像让我想到(a-b)^2 = a^2 - 2ab + b^2
由于这题 N (0 < N ≤ 100),所以O(N^4)可以接受
本题代码如下
#include <bits/stdc++.h>
using namespace std;int a[105][105], ss[105][105];int main()
{int n;scanf("%d", &n);for (int i = 1; i <= n; i++)for (int j = 1; j <= n; j++)scanf("%d", &a[i][j]);for (int i = 1; i <= n; i++)ss[1][i] = ss[1][i - 1] + a[1][i];for (int j = 1; j <= n; j++)ss[j][1] = ss[j - 1][1] + a[j][1];for (int i = 2; i <= n; i++)for (int j = 2; j <= n; j++)ss[i][j] = ss[i - 1][j] + ss[i][j - 1] - ss[i - 1][j - 1] + a[i][j];int ans = 0;for (int i = 1; i <= n; i++)for (int j = 1; j <= n; j++)for (int u = 1; u < i; u++)for (int v = 1; v < j; v++){int gf = ss[i][j] - ss[u - 1][j] - ss[i][v - 1] + ss[u - 1][v - 1];ans = max(gf, ans);}printf("%d\n", ans);return 0;
}