历届试题 最大子阵
时间限制:1.0s 内存限制:256.0MB
问题描述
给定一个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。
解题思路:
想想类似的题型,求一个一维数组的最大连续和,这个应该是不难的。代码如下:
//max是最后结果,arr是数组,m是arr数组长度
int max = Integer.MIN_VALUE;
void getMax(int[] arr, int m) {
int temp = 0;
for(int mi=0;mi<m;++mi) {
temp += arr[mi];
max = max>temp?max:temp;
if(temp < 0)temp = 0;
}
}
现在的情况就是把一维拓展成了二维数组,因为最后要求的是矩阵,也就是说只要把矩阵压缩成一个一维数组就好了,三层循环:1、起始的行数,2、终止的行数,3、每列。然后把每次生成的一位数组求最大连续和,找到所有max的最大值。
说起来好像也没用到动态规划。。。。
反思错误:
①幸亏这题的数据量不大,不然我的方法绝对超时【O(m n^2)】
②因为题型是动态规划,一直向动态规划的想法上靠,结果没想出来。我这解法也不算动态规划,挂羊头卖狗肉了。不过动态规划的最大子矩阵问题是可以这么解的。
Java代码:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) {
// long sta = System.nanoTime();
InputStream is = System.in;
OutputStream os = System.out;
IN cin = new IN(is);
PrintWriter cout = new PrintWriter(os);
SO so = new SO();
so.solution(cin, cout);
// long end = System.nanoTime();
// cout.println("耗时:" + (double)(end-sta)/1e6 + "ms");
cout.close();
}
static final int MOD = (int)1e9 + 7;
//实际代码开始的类--------------------------------------------------
static class SO {
int max = Integer.MIN_VALUE;
void getMax(int[] arr, int m) {
int temp = 0;
for(int mi=0;mi<m;++mi) {
temp += arr[mi];
max = max>temp?max:temp;
if(temp < 0)temp = 0;
}
}
void solution(IN cin, PrintWriter cout) {
int n = cin.nextInt(), m = cin.nextInt();
int[][] mat = new int[n][m];
int[] arr = new int[m];
for(int ni=0;ni<n;++ni) {
for(int mi=0;mi<m;++mi) {
mat[ni][mi] = cin.nextInt();
}
}
for(int sni=0;sni<n;++sni) {
Arrays.fill(arr,0);
for(int eni=sni;eni<n;++eni) {
for(int mi=0;mi<m;++mi) {
arr[mi] += mat[eni][mi];
}
getMax(arr,m);
}
}
cout.println(max);
}//end solution
}//end SO
//以下是快读部分
static class IN {
private BufferedReader reader;
private StringTokenizer tokenizer;
IN(InputStream is) {
reader = new BufferedReader(new InputStreamReader(is), 32768);
tokenizer = null;
}
public String next() {
while (tokenizer == null || !tokenizer.hasMoreTokens()) {
try {
tokenizer = new StringTokenizer(reader.readLine());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return tokenizer.nextToken();
}
public int nextInt() {
return Integer.parseInt(next());
}
public long nextLong() {
return Long.parseLong(next());
}
public double nextDouble() {
return Double.parseDouble(next());
}
}
}