以前のテストの質問の最大の部分行列
問題の説明
n * mの行列Aが与えられた場合、この部分行列の要素の合計を最大化するために、Aで空でない部分行列を見つけます。
その中で、Aの部分行列は、行と列が連続しているAのブロックを指します。
入力形式入力
の最初の行には、行列Aの行数と列数をそれぞれ表す2つの整数n、mが含まれています。
次のn行、各行はm個の整数で、行列Aを表します。
出力形式
Aの最大の部分行列の要素の合計を表す、整数を含む行を出力します。
入力例:
3 3
-1 -4 3
3 4 -1
-5 -2 8
サンプル出力:10
サンプルの説明
最後の列を取得すると、合計は10になります。
データのスケールと規則データの
50%、1 <= n、m <= 50
の場合、データの100%、1 <= n、m <= 500の場合、Aの各要素の絶対値は5000を超えません。
アイデア:レイヤーiからレイヤーjまでの垂直シーケンスの合計を見つけるために使用される各列のプレフィックスの合計を見つけ、次に最大の水平サブシーケンスの合計を見つけて最大のサブ配列の合計を形成します
import java.util.Scanner;
public class Main4 {
static int[][] map;
static int[][] cmap;
static int[] rmap;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
map = new int[n + 1][m + 1];
cmap = new int[n + 1][m + 1];
rmap = new int[m + 1];
int ans = Integer.MIN_VALUE;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
map[i][j] = sc.nextInt();
// 前缀和
cmap[i][j] = cmap[i - 1][j] + map[i][j];
}
}
for (int i = 0; i <= n; i++) {
for (int j = i + 1; j <= n; j++) {
for (int k = 1; k <= m; k++) {
// i层到j层的纵向和
rmap[k] = cmap[j][k] - cmap[i][k];
}
// 求横向最大子序列和
for (int k = 1; k <= m; k++) {
if (rmap[k - 1] > 0)
rmap[k] += rmap[k - 1];
if (rmap[k] > ans)
ans = rmap[k];
}
}
}
System.out.println(ans);
}
}