看完王道书学着打了一遍求最大子矩阵的代码,代码还是要亲手打才能真正理解啊,加了超级详细的注释,能理解怎么求一维最大子序列和的应该都能看懂。
题目描述
已知矩阵的大小定义为矩阵中所有元素的和。给定一个矩阵,你的任务是找到最大的非空(大小至少是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
#include<iostream>
using namespace std;
int num[100][100]={{0}};//输入的矩阵
int tmp[100][100]={{0}};//辅助矩阵,[i,j]值为原矩阵第j列从第0行到第i行累加得到(设置的目的是减少后续计算)
int dp_vol[100]={0};//记录从i行累加到j行得到的值,在getdp(int n)中一个for(j)循环刷新一次
int dp_row[100]={0};//针对某次循环得到的一个dp_vol数组,建立求最大连续序列和所需的dp数组
int rowdp(int n){//针对某次循环得到的一个dp_vol数组,建立求最大连续序列和所需的dp数组dp_row
int rowmax=0;
for(int i=0;i<n;i++){//此处类比一维的求最大连续序列和问题,dp_vol相当于最大连续序列和问题中用户输入的数组
if(i==0)dp_row[i]=dp_vol[i];//dp_row相当于求最大连续序列和问题中的dp数组
else{
dp_row[i]=max(dp_row[i-1],0)+dp_vol[i];
}
if(dp_row[i]>rowmax)rowmax=dp_row[i];
}
return rowmax;
}
int getdp(int n){//遍历每一种选择矩阵行(hang)的方案,每次得到的dp_vol数组后调用rowdp(int n)
int maxnum=0;//记录全局最大子矩阵和
for(int i=0;i<n;i++){//i,j,k含义:i:从第i行,j:到第j行, k:该行的第k个元素
for(int j=i;j<n;j++){//j最小等于k!因是从i行到j行,即j不能小于i
for(int k=0;k<n;k++){
//tmp矩阵的作用在这里显现,这里需要求从i行累加的j行的各列元素的值
//如果没有tmp矩阵直接用num矩阵算,会有大量且重复的计算,比如求第1行到第6行和求第2行到第7行
//有了tmp以后,i行累加的j行的各列元素的值就等于tmp[j][k]-tmp[i-1][k]
if(i==0)
dp_vol[k]=tmp[j][k];//如果从第0行开始,则直接等于tmp矩阵对应行的值
else
dp_vol[k]=tmp[j][k]-tmp[i-1][k];
}
int rowmax=rowdp(n);//注意调用是在一轮j循环的末尾
maxnum=max(rowmax,maxnum);
}
}
return maxnum;
}
int main(){
int n;
while(cin>>n){
//初始化num数组和tmp数组
for(int i=0;i<n;i++){
cin>>num[0][i];
tmp[0][i]=num[0][i];
}
for(int i=1;i<n;i++)
for(int j=0;j<n;j++){
cin>>num[i][j];
tmp[i][j]=num[i][j]+tmp[i-1][j];
}
cout<<getdp(n)<<endl;
}
}