题目:
历届试题 最大子阵
时间限制: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。
思路:
可以参照求解最大子序列和的问题时算法(动态规划),把二维数组转为一维数组求最大值。
行、列必须输连续的,那么可以先求出每一列的前n项和,存入sum[]数组,然后再按照动态规划思想,求每一列的最大和。
对应dp[]有
//如果前一个dp值<=0,则不进行累加(加上负值肯定变小)
dp[j] = sum[j]; dp[j-1]<=0
//如果>0,则进行累加(即当前列加上前一列)
dp[j] = dp[j-1]+sum[j]; dp[j-1]>0
如样例:
那么,从这张图,我们可以看出,第i行的和=前i-1行+第i行,动态规划思想,sum[]已经存储子问题的解。
求解:
第一次用了三个for,超时了。用两个for还是超时了。。。。
package 蓝桥练习;
import java.util.Arrays;
import java.util.Scanner;
/**
* 思路:采用求解最大子序列和的问题时算法
* 注意:把二维数组转为一维数组求解(A的子矩阵指在A中行和列均连续的一块。 )
* @author lym
*
*/
public class 最大矩阵和 {
static Integer INF = Integer.MIN_VALUE; //表示无穷小
static int MAX = 505;
static int[][] a = new int[MAX][MAX];
static int[] sum = new int[MAX]; //存储第i列的前n行的和
static int[] dp = new int[MAX]; //动态数组,将二维数组转为一维数组
static int maxSum = INF; //存储最大矩阵和
static void fun(int n, int m) {
for(int st=1; st<=n; st++) { //st为开始行
Arrays.fill(sum,0); //初始化sum数组,赋值为0
for(int i=st; i<=n; i++) { //i为结束行,从st行加到i行
for(int j=1; j<=m; j++) { //累加第j列的前n项和
sum[j] += a[i][j];
dp[1] = sum[1]; //设置动态数组的第一个值为sum[1],为了便于下面的比较
if(dp[1] > maxSum) //保证maxSum为最大值
maxSum = dp[1];
if(j==1) //为1时,跳过下面的计算
continue;
else {
if(dp[j-1] < 0) //如果前一个dp值<=0,则不进行累加(加上负值肯定变小)
dp[j] = sum[j];
else //如果>0,则进行累加(即当前列加上前一列)
dp[j] = dp[j-1]+sum[j];
if(dp[j] > maxSum) //保证maxSum为最大值
maxSum = dp[j];
}
}
}
}
}
/* 三个for的写法,与两个for的差别不大
static void fun(int n, int m) {
for(int st=1; st<=n; st++) { //st为开始行
Arrays.fill(sum,0); //初始化sum数组,赋值为0
for(int i=st; i<=n; i++) { //i为结束行,从st行加到i行
for(int j=1; j<=m; j++) { //累加第j列的前n项和
sum[j] += a[i][j];
}
dp[1] = sum[1]; //设置动态数组的第一个值为sum[1],为了便于下面的比较
if(dp[1] > maxSum) //保证maxSum为最大值
maxSum = dp[1];
for(int j=2; j<=m; j++) { //求解最大段和
if(dp[j-1] < 0) //如果前一个dp值<=0,则不进行累加(加上负值肯定变小)
dp[j] = sum[j];
else //如果>0,则进行累加(即当前列加上前一列)
dp[j] = dp[j-1]+sum[j];
if(dp[j] > maxSum) //保证maxSum为最大值
maxSum = dp[j];
}
}
}
}*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner input = new Scanner(System.in);
int n = input.nextInt();
int m = input.nextInt();
input.nextLine();
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
a[i][j] = input.nextInt();
fun(n, m);
System.out.println(maxSum);
}
}
运行结果:
这道题也想了蛮久的,参考了这位博客的思路:https://blog.youkuaiyun.com/huanhuanxiaoxiao/article/details/54924634
有大神有优化思路可以分享下,,,嘻嘻