列表

详情


DP10. 最大子矩阵

描述

已知矩阵的大小定义为矩阵中所有元素的和。给定一个矩阵,你的任务是找到最大的非空(大小至少是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

原站题解

C++14 解法, 执行用时: 4ms, 内存消耗: 296KB, 提交时间: 2018-07-08

#include<cstdio>
#include<cstring>

int n;
int a[110][110];
int b[110];

int main()
{
    //printf("123\n");
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=0; i<n; i++)
            for(int j=0; j<n; j++)
                scanf("%d",&a[i][j]);

        int Max = -32767;
        for(int i=0; i<n; i++)
        {
            //数组b表示i~j行,对应列元素的和
            //将二维动态规划问题转化为一维动态规划问题
            memset(b, 0, sizeof(b));
            for(int j=i; j<n; j++)
            {
                //下面是针对数组b求最大子段和的动态规划算法
                int sum=0;
                for(int k=0; k<n; k++)
                {
                    b[k] += a[j][k];
                    sum += b[k];

                    if(sum>Max) Max = sum;
                      if(sum<0) sum=0;

                }
            }
        }
        printf("%d\n",Max);
    }

    return 0;
}

C 解法, 执行用时: 4ms, 内存消耗: 304KB, 提交时间: 2021-03-03

#include<stdio.h>
#include<string.h>
#define INF 1E9
 
int matrix[101][101];
int n,maxSum;
int buf[101];
 
int max(int a,int b){
    return a>b?a:b;
}
int findMax(){
    int i;
    int M;
    int dp[101]={0};
    dp[0]=buf[0];
    for(i=1;i<n;i++){
        dp[i]=max(dp[i-1]+buf[i],buf[i]);
    }
    M=dp[0];
    for(i=1;i<n;i++)
        M=max(dp[i],M);
    return M;
}
 
int main(){
    int i,j,k;
    while(scanf("%d",&n)!=EOF){
        if(n<=0){break;}
        maxSum=-INF;
        for(i=0;i<n;i++){
            for(j=0;j<n;j++){
                scanf("%d",&matrix[i][j]);
            }
        }
        for(i=0;i<n;i++){
            memset(buf,0,sizeof(buf));
            for(j=i;j<n;j++){
                for(k=0;k<n;k++){
                    buf[k]+=matrix[j][k];
                }
                maxSum=max(findMax(),maxSum);
            }
        }
        printf("%d\n",maxSum);
    }
}

C 解法, 执行用时: 4ms, 内存消耗: 304KB, 提交时间: 2019-02-17

#include<stdio.h>
#include<memory.h>
int sum[100];
int dp[100]={0};
int getResult(int n){
	dp[0]=sum[0];
	for(int i = 1;i<n;i++){
		dp[i]=(dp[i-1]+sum[i])>sum[i]?(dp[i-1]+sum[i]):sum[i];
	}
	int max = -127;
	for(int i = 0;i<n;i++){
		if(dp[i]>max){
			max =dp[i];
		}
	}
	return max;
}
int main(){
	int n;
	int matrix[100][100];
	while(scanf("%d",&n)!=EOF){
		for(int i = 0;i<n;i++){
			for(int j = 0;j<n;j++){
				scanf("%d",&matrix[i][j]);
			}
		}
		int ans = -127;
		for(int i = 0;i<n;i++){
			memset(sum,0,sizeof(sum));
			for(int j = i;j<n;j++){
				for(int k = 0;k<n;k++){
					sum[k] += matrix[j][k];
				}
				int temp = getResult(n);
				if(temp > ans){
					ans = temp;
				}
			}
		}
		printf("%d\n",ans);
	}
}

C 解法, 执行用时: 4ms, 内存消耗: 316KB, 提交时间: 2019-03-25

/*最大子矩阵和,思路:因为是二维的,倒是无法像一维那样dp解决
想到用压缩二维矩阵(就是从上往下加)成一维以题中给出的用例为例,按行压缩得到一个一维数组,然后
从左往右加过去,一旦sum<0从新累加, 等遍历完所有就能比出最大那个值了 
*/
#include<stdio.h>
#include<string.h>
#define INF 1E9

int matrix[101][101];
int n,maxSum;//n是输入的矩阵大小,max保存着最大那个
int buf[101];//保存着每个压缩行的值 

int max(int a,int b){
    return a>b?a:b;
}
//常规的找最大连续子序列和操作
int findMax(){
    int i;
    int M;
    int dp[101]={0};
    dp[0]=buf[0];
    for(i=1;i<n;i++){
        dp[i]=max(dp[i-1]+buf[i],buf[i]);
    }
    M=dp[0];
    for(i=1;i<n;i++)
        M=max(dp[i],M);
    return M;
}

int main(){
    int i,j,k;
    while(scanf("%d",&n)!=EOF){
        if(n<=0){break;}
        maxSum=-INF;//初始话最大值
        for(i=0;i<n;i++){
            for(j=0;j<n;j++){
                scanf("%d",&matrix[i][j]);
            }
        }
        //前面是输入矩阵操作
        for(i=0;i<n;i++){
            memset(buf,0,sizeof(buf));
            /*
			第一轮从第一行开始往下依次合并n-0行
			第二轮从第二行开始往下依次合并n-1行
			……
			每一轮开始前buf都要重新置0 
			*/
            for(j=i;j<n;j++){
                for(k=0;k<n;k++){//这是表示列数
                    buf[k]+=matrix[j][k];
                }
                //对每次的buf进行一次是否最大比较
                maxSum=max(findMax(),maxSum);
            }
        }
        printf("%d\n",maxSum);
    }
}

C 解法, 执行用时: 4ms, 内存消耗: 320KB, 提交时间: 2022-03-04

#include<stdio.h>
#include<string.h>
#define MAX(a,b)(a>b?a:b)
#define INF 0x3f3f3f3f
#define N 105
int nums[N][N];
int buf[N];
int n,max;
int findMax(buf[],n){
    int i;
    int result=buf[0];
    int dp[n+1];
    memset(dp, 0, sizeof(dp));
    for(i=1;i<n+1;i++){
        dp[i]=MAX(dp[i-1]+buf[i-1],buf[i-1]);
 
       result = MAX(result, dp[i]);   //更新最大连续子序列和 
   }
   return result;
}
int main(){
    int i,j,k;
    while(scanf("%d",&n)!=EOF){
        if(n<=0){
            break;
        }
        max=-INF;
        for(i=0;i<n;i++){
            for(j=0;j<n;j++){
                scanf("%d",&nums[i][j]);
            }
        }
        for(i=0;i<n;i++){
            memset(buf,0,sizeof(buf));
            for(j=i;j<n;j++){
                for(k=0;k<n;k++){
                    buf[k]+=nums[j][k];
                }
                max=MAX(findMax(buf,n), max);
            }
        }
        printf("%d\n",max);
    }
}

上一题