1464055387
问题描述
给定一个n*m的矩阵A,求A中的一个非空子矩阵,使这个子矩阵中的元素和最大。
其中,A的子矩阵指在A中行和列均连续的一块。
输入格式
输入的第一行包含两个整数n, m,分别表示矩阵A的行数和列数。
接下来n行,每行m个整数,表示矩阵A。
输出格式
输出一行,包含一个整数,表示A中最大的子矩阵中的元素和。
样例输入
3 3
-1 -4 3
3 4 -1
-5 -2 8
样例输出
10
样例说明
取最后一列,和为10。
数据规模和约定
对于50%的数据,1<=n, m<=50;
对于100%的数据,1<=n, m<=500,A中每个元素的绝对值不超过5000。
解题思路
像题目要求最大什么什么,大多都用Dp。其实刚刚接到题目我也有点慌了,自己最不拿手就是Dp,像这道题,矩阵无非就是用一个二维数组存储的数据,
那么先要对矩阵进行压缩,可以以行为主序,也可以以列为主序,拿行来举例
2 5 -1
7 -5 3
0 8 -11
这一组数据,我们很容易可以看出来最大子矩阵是17
2 5
7 -5
0 8
没错,这是一个最大的子矩阵,其实你可以这样去分解他,以行为主序那他就成了
9 8 -8
这不就成了求最大子段问题啦,哈哈,没想到吧
那么就要对他进行压缩了,一开始我没想到有更好的办法,只好每两个列的差值都存储,但后来发现了一个巧妙的方法,那就是取他的行差或者列差
像上面的数据,可以这样进行压缩,就是把每列的值够累计相加,得出以下的数据
2 5 -1
9 0 2
9 8 -8
很容易理解,第一行就是原来矩阵第一行的子矩阵,最后一行就是整个矩阵,第二行就是原来矩阵的第一第二行压缩出来的,如果想得到原来矩阵的第二第三行压缩矩阵,那么拿压缩后的矩阵的第三行减第一行,有没有。哈哈
代码实现
import java.util.Scanner;
/**
最大子矩阵
@author Ape
/
public class MaxJz {static int[][] a = new int[510][510];
static int n, m, t, sum, max;public static void main(String[] args) {
Scanner scanner = new Scanner(System.in); n = scanner.nextInt(); m = scanner.nextInt(); for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { t = scanner.nextInt(); a[i][j] = a[i - 1][j] + t; // 压缩矩阵 } max = Integer.MIN_VALUE; for (int i = 1; i <= n; i++) for (int j = i; j <= n; j++) { sum = 0; for (int k = 1; k <= m; k++) { t = a[j][k] - a[i - 1][k]; // 计算第i行到第j行的差 if (sum > 0) sum += t; else sum = t; if (sum > max) max = sum; } } System.out.println(max); scanner.close();
}
}
ps:距离第七届蓝桥杯决赛还有3天