最大子矩阵和

来源:互联网 发布:如何开淘宝话费充值店 编辑:程序博客网 时间:2024/04/27 19:26

前言:

今日在打比赛时遇到了一道求最大子矩阵的题目,对于渣渣的我非常困难。在网上查找,发现很少有博客是讲得清晰的。所以决定自作一篇有关于此的博客。

题目:

给定一个矩阵,都是整数,其中(n≤500),求出其中的最大子矩阵

解题思路:

O(n^2*n^2*n^2)的做法:

很容易想到,可以枚举一个矩阵的左上角和右下角的坐标确定这个矩阵,然后,再用两个循环进行统计

O(n^2*n^2)的做法:

对于上面的方法,提前处理一个前缀和,即可省去后面统计的时间复杂度。

正解,即O(n³)事实上并没有这么多

想要做对这道题,我们先要明白一个最大子段和算法的做法:

例如数字a={8,-2,3,-11,5},我们需要求出一段连续数字的最大和是什么

我们的思想是DP

设f[i]表示从1~i这些位置中的最大子段和

如何转移?对于当前的点i,我们只有两种状态,选择与上一个子段和连接或者自己重新构成一个字段和。

若选,则与1~i-1的最大字段和有关系,即1~i-1的最长字段和加上当前的a[i],重新构成一个子段和

若不选,则与1~i-1最大子段和没有关系,自己重新构成了一个字段和

两者取之小者,亦可解决

列出状态转移方程:f[i]:=max(a[i],f[i-1]+a[i])

时间复杂度 O(n)

---------------------------------分界线-----------------------

有了前面的铺垫,那么这道题就容易多了。

我们可以根据最大子段和,求出最大子矩阵和,无非就是1维改成了2维

我们先选择一连串几行数,把他们每一列累加起来,即最大子段和中的a数组(这里可以用前缀和实现),然后按照如上做法实现即可。

对于选择一连串行数,我们需要两个循环

i表示选择多少行连续的数 O(n)

j表示从第j行开始往下选i行 O(n)没有这么多

最后做一次最长子段和O(n),即O(n³)

代码实现:

uses math;var        n,m,i,j,k,maxnum,maxn,ans:longint;        a,s:array[0..500,0..500] of longint;        f:array[0..500] of longint;begin        readln(n,m);        for i:=1 to n do                for j:=1 to m do                begin                        read(a[i,j]);                        s[i,j]:=s[i-1,j]+a[i,j];//前缀和                end;        for i:=1 to n do                for j:=1 to n-i+1 do//如上                begin                        fillchar(f,sizeof(f),0);                        maxnum:=0;                        for k:=1 to m do//最大子段和                        begin                                f[k]:=max(f[k-1]+s[j+i-1,k]-s[j-1,k],s[j+i-1,k]-s[j-1,k]);                                if f[k]>maxnum then                                        maxnum:=f[k];                        end;                        if maxnum>maxn then                                maxn:=maxnum;                end;        writeln(maxn);end.
若有不懂的地方可以在下方评论中提出来。

2 0