最大子矩阵

题目描述
已知矩阵的大小定义为矩阵中所有元素的和。给定一个矩阵,你的任务是找到最大的非空(大小至少是1 * 1)子矩阵。 比如,如下4 * 4的矩阵 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]。

输出描述:
测试数据可能有多组,对于每组测试数据,输出最大子矩阵的大小。

示例1
输入
4
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
输出
15

题目解析:将矩阵按列分开,如果相邻的矩阵列的和>0,那么加上肯定比原来的大,如果<0,比大小,留下大的。所以只用两层循环就够了,从每一行开始的得到最大矩阵,然后得出结论。

代码:

#include <stdio.h>
#include <string.h>
#define MAX(a, b) (a > b ? a : b)
#define N 105
#define INF 0x3f3f3f3f
int martix[N][N];           //存储矩阵
int buf[N];                 //将相邻若干行合并成一行以后的结果
int n, maxSum;              //n是矩阵大小,maxSum是最大矩阵和
  
// 这里就是求解最大连续子段和
int findMax() {
   int i;
   int result = buf[0], sum = buf[0];
   for (i = 1; i < n; i++) {
       if (sum <= 0) {
           sum = buf[i];            //如果前面位置最大连续子序列和小于等于0,则以当前位置i结尾的最大连续子序列和为buf[i]  
       } else {
           sum += buf[i];           //如果前面位置最大连续子序列和大于0,则以当前位置i结尾的最大连续子序列和为它们两者之和
       }    
 
       result = MAX(result, sum);   //更新最大连续子序列和  
   }
   return result;
}

int main() {
    int i, j, k;
    while(scanf("%d", &n) != EOF) {
        maxSum = -INF;
        for(i = 0; i < n; i++) {
            for(j = 0; j < n; j++) {
                scanf("%d", &martix[i][j]);
            }
        }
        
        for(i = 0; i < n; i++) {    //从行开始切割矩阵 
            // 数组b表示j ~ n - 1行,对应列元素的和
            // 将二维动态规划问题转化为一维动态规划问题
            memset(buf, 0, sizeof(buf));
            for(j = i; j < n; j++) {        
                for(k = 0; k < n; k++) {    
                    buf[k] += martix[j][k];
                }
                maxSum = MAX(findMax(), maxSum);
            }
        }
        printf("%d\n", maxSum);
    }
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值