题目要求
给定一个m行n列的整数矩阵A,试求矩阵A的一个子矩阵,使其各元素之和为最大。
一维子段和
要解上面的二维问题,得先会一维的。一维的很简单,设dp[i]表示前i个数中,一定包括i的最大子段和。显然方程
d
p
[
i
]
=
(
d
p
[
i
−
1
]
<
=
0
)
?
a
[
i
]
:
(
d
p
[
i
−
1
]
+
a
[
i
]
)
dp[i]=(dp[i-1]<=0)?a[i]:(dp[i-1]+a[i])
dp[i]=(dp[i−1]<=0)?a[i]:(dp[i−1]+a[i])成立。然后一维的答案就是max(dp[i])。
这样一维的复杂度是O(n)的。
二维子矩阵和
二维问题如果暴力枚举左上角和右下角,决定子矩阵的位置后用矩阵的前缀和可以O(1)得到子矩阵的和。这样复杂度是
O
(
n
3
)
O(n^3)
O(n3)。
但是如果只枚举上下界up,down,上下界确定后就可以用列的前缀和O(n)的构造出一个一维序列a,这个序列满足
a
i
=
∑
k
=
u
p
d
o
w
n
m
t
r
x
(
i
,
k
)
=
s
u
m
(
d
o
w
n
,
i
)
−
s
u
m
(
u
p
−
1
,
i
)
a_i=\sum_{k=up}^{down}mtrx(i,k)=sum(down,i)-sum(up-1,i)
ai=k=up∑downmtrx(i,k)=sum(down,i)−sum(up−1,i)其中
s
u
m
(
x
,
y
)
=
∑
i
=
1
x
m
t
r
x
(
i
,
y
)
sum(x,y)=\sum_{i=1}^{x}mtrx(i,y)
sum(x,y)=i=1∑xmtrx(i,y)
然后O(n)求这个a序列的最大字段和,就是对应上下界的最优值。这样枚举的上下界一共
O
(
n
2
)
O(n^2)
O(n2)对,在乘上求一维子段的复杂度,时间复杂度是
O
(
n
3
)
O(n^3)
O(n3)。
代码
import java.util.*;
public class App {
static final int NN=210;
static int[][] a=new int[NN][NN];
static long[] dp=new long[NN],b=new long[NN];
static long[][] sumc=new long[NN][NN];
static final long oo=1000000000000000000l;
public static void main(String[] args) throws Exception {
Scanner sc=new Scanner(System.in);
int n=sc.nextInt(),m=sc.nextInt();
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){
a[i][j]=sc.nextInt();
sumc[i][j]=sumc[i-1][j]+a[i][j];
}
long ans=-oo;
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){
dp[0]=0;b[0]=0;
for(int k=1;k<=m;k++){
b[k]=sumc[j][k]-sumc[i-1][k];
dp[k]=(dp[k-1]<=0)?b[k]:(b[k]+dp[k-1]);
ans=Math.max(ans,dp[k]);
}
}
}
System.out.printf("%d\n",ans);
}
}