为了更好的阅读体检,可以查看我的算法学习网
在线评测链接:P1443
题目内容
小美有一个矩形的蛋糕,共分成了 n n n 行 m m m列,共 n ∗ m n * m n∗m个区域,每个区域是一个小正方形,已知蛋糕每个区域都有一个美味度。她想切一刀把蛋糕切成两部分,自己吃一部分,小团吃另一部分。
小美希望两个人吃的部分的美味度之和尽可能接近,请你输出| s i − s 2 s_i - s_2 si−s2|的最小值。(其中 S 1 S_1 S1代表小美吃的美味度, s 2 s_2 s2代表小团吃的美味度)
请务必保证,切下来的区域都是完整的,即不能把某个小正方形切成两个小区域。
输入描述
第一行输出两个正整数 n n n和 m m m,代表蛋糕区域的行数和列数。
接下来的 n n n行,每行输入 m m m个正整数 a i j a_{ij } aij,用来表示每个区域的美味度。
输出描述
第一行输出两个正整数 n n n和 m m m,代表蛋糕区域的行数和列数。
接下来的 n n n行,每行输入 m m m个正整数 a i j a_{ij } aij,表示每个区域的美味度。
1 ≤ n , m ≤ 1 0 3 1 \leq n,m \leq 10_3 1≤n,m≤103
1 ≤ a i j ≤ 1 0 4 1 \leq a_{ij } \leq 10_4 1≤aij≤104
样例
输入输出示例仅供调试,后台判题数据一般不包含示例
输入
2 3
1 1 4
5 1 4
输出
0
说明
把蛋糕像这样切开:
11
11
11|
4
4
4
思路:前缀和
由于规定只能横切或竖切一刀,因此借助二维前缀和对横切和竖切的长度进行枚举,求最小的差值即可。
时间复杂度 O ( N 2 ) O(N^2) O(N2)
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int maxn = 1010; // maxn is not used in the code
int n, m;
long[][] pre = new long[maxn][maxn];
n = scanner.nextInt();
m = scanner.nextInt();
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
pre[i][j] = scanner.nextLong();
pre[i][j] += pre[i - 1][j] + pre[i][j - 1] - pre[i - 1][j - 1];
}
}
long ans = 1000000000L; // 1e9
for (int i = 1; i < n; ++i) {
ans = Math.min(ans, Abs(pre[i][m], pre[n][m] - pre[i][m]));
}
for (int j = 1; j < m; ++j) {
ans = Math.min(ans, Abs(pre[n][j], pre[n][m] - pre[n][j]));
}
System.out.println(ans);
}
public static long Abs(long a, long b) {
return a > b ? a - b : b - a;
}
}