一、题目
题目描述:现给出一个N*N矩阵,要求求出拥有最大和的子矩阵的和。例子如下图所示:
它的最大子矩阵的和为15;
二、解题思路
此题的解法与动态规划经典题目——最大连续子序列之和题目思想一样,只不过本题是二维空间上的拓展。N*N矩阵用二维数组a[N][N]表示。我们解决新问题的方法是借鉴我们以前解决过的类似问题的方法和思路,当然本题也不例外,通过思考可以发现,这道题目与动态规划经典题目——最大连续子序列之和非常相似,只不过动态规划经典题目——最大连续子序列之和它是一维的问题,而本题目是二维问题,我们是否能把二维问题转化为一维问题吗?通过认真的考虑是可以的,我们可以把每列的元素进行合并为一个元素(可以定义二维数组sum[][],其中sum[i]表示前i行每列数字相加的和,所以sum[j][] - sum[i][]为一维向量),这样运用动态规划经典题目——最大连续子序列之和的思想了。
①定义状态
根据上面的分析,我们定义二维数组dp[i][j]表示第i行到第j行中的最大子矩阵和。所以我们要求的最大子矩阵和为max(dp[i][j])其中0≤i≤j≤N;
②定义状态转移方程
大家知道动态规划满足无后向性,即:每个阶段的决策仅受之前决策的影响,但是不影响之后各阶段的决策。所以我们可以从后往前推出状态转移方程,具体定义可参考动态规划经典题目——最大连续子序列之和中的状态转移方程。
三、代码编写
#include <stdio.h>
#include <stdlib.h>
#define N 4
#define max(a,b) ((a > b)?a:b)
int main()
{
//定义矩阵
int a[N][N] = { {0,-2,-7,0},
{9,2,-6,2},
{-4,1,-4,1},
{-1,8,0,-2}};
//定义二维数组sum[][],其中sum[i]表示前i行每列数字相加的和,
//所以sum[j][] - sum[i][]为一维向量
int sum[N+1][N] = {0};
int temp = 0 ;
//保存最大子矩阵和
int maxResult = 0;
//给sum数组赋值
int i,j,k;
for(i=1 ; i < N+1 ; i++){
for(j=0 ; j < N ; j++){
sum[i][j] = sum[i-1][j] + a[i-1][j];
}
}
//核心算法
for(i=0 ; i < N ; i++){
for(j=i+1 ; j < N+1 ; j++){
temp = 0 ;
for(k=0 ; k < N ; k++){
temp += (sum[j][k] - sum[i][k]);
if(temp > maxResult){
maxResult = temp;
}
if(temp < 0){
temp = 0;
}
}
}
}
printf("最大子矩阵和为:%d",maxResult);
return 0;
}
四、运行结果