126.最大額
整数を含む2次元行列が与えられた場合、サブ長方形は、1 * 1
配列全体の中でサイズ以上の連続したサブ配列です。
長方形の合計は、長方形内のすべての要素の合計です。
この問題では、合計が最大のサブ長方形は最大サブ長方形と呼ばれます。
たとえば、次の配列:
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
最大のサブ長方形は次のとおりです。
9 2
-4 1
-1 8
最大合計は15です。
入力フォーマット
入力にはN ∗ NN * Nが含まれますN∗Nの整数配列。
最初の行に整数NNのみを入力しますNは、正方形の2次元配列のサイズを表します。
2行目から、スペースと改行で区切ってN 2 N ^ 2と入力します。N2つの整数、2次元配列ではN 2 N ^ 2N2つの要素、入力シーケンスは2次元配列の最初の行から始まり、行ごとに入力され、同じ行のデータが左から右に1つずつ入力されます。
配列内の数値は[-127,127]の範囲のままになります。
出力形式
最大のサブ長方形の合計を表す整数を出力します。
データ範囲
1≤N≤1001≤N≤1001≤N≤。1つの0 0
入力サンプル:
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
サンプル出力:
15
アイデア
位置s[i][j]
から(0,0)
位置の(i,j)
すべての要素までを表し、s[i][j]
次のように計算されたとします。
次に(x1, y1)
、左上隅、(x2, y2)
:需要のサブマトリックス右下隅、および以下に示すようにどのようになりますか?
2次元配列が前に付けられますそして、すべての部分行列を列挙し、最大値を見つけるだけで済みます。
Javaコード
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[][] arr = new int[n + 1][n + 1];//避免下标转换
int[][] s = new int[n + 1][n + 1];//前缀和数组
//读取数据
for(int i = 1;i <= n ;i++){
for(int j = 1;j <= n;j++){
arr[i][j] = scanner.nextInt();
}
}
//计算二维前缀和s[i][j] = s[i-1][j] + s[i][j-1] - s[i-1][j-1] + arr[i][j]
//这里就显示了我们将下标设置为成1开始的优势了,i - 1最小也是0,而s[0][j]默认都是0,公式中加上0也没事
//但如果下标从0开始,则s[i-1][j]中的i-1可能会下标越界,需要我们特判,增加麻烦
for(int i = 1;i <= n;i++){
for(int j = 1;j <= n;j++){
s[i][j] = s[i-1][j] + s[i][j-1] - s[i-1][j-1] + arr[i][j];
}
}
int res = Integer.MIN_VALUE;
for(int x2 = 1;x2 <= n;x2++){
for(int y2 = 1;y2 <= n;y2++){
//枚举子矩阵的右下角(x2,y2)
for(int x1 = 1;x1 <= x2;x1++){
for(int y1 = 1;y1 <= y2;y1++){
//枚举子矩阵的左上角(x1,y1) 注for中条件为: (x1,y1)<= (x2,y2)
res = Math.max(res,s[x2][y2] - s[x1 -1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1]);
}
}
}
}
System.out.println(res);
}
}