小M的蛋糕切割问题
问题描述
小M有一个 n×mn×m 的矩形蛋糕,蛋糕被分为 n×mn×m 个区域,每个区域都有一个美味度。她希望通过一刀将蛋糕切成两部分,一部分自己吃,另一部分给小团。切下的区域必须是完整的,即不能把某个小正方形切成两个小区域。
小M希望两个人吃的部分的美味度之和尽量接近。你的任务是计算出美味度差的最小值,即 ∣s1−s2∣∣s1−s2∣ 的最小值,其中 s1s1 是小M吃到的美味度,s2s2 是小团吃到的美味度。
问题理解
我们需要将一个 n×m 的矩形蛋糕切成两部分,使得两部分的美味度之和尽量接近。切割必须是完整的,即不能把某个小正方形切成两个小区域。我们的目标是找到一种切割方式,使得两部分的美味度之和的差值最小。
数据结构选择
由于我们处理的是一个二维数组,我们可以直接使用二维数组来存储蛋糕的美味度。
算法步骤
- 计算总和:首先计算整个蛋糕的美味度总和
totalSum
。 - 水平切割:遍历所有可能的水平切割线(从第1行到第n-1行),计算切割线上方的部分的美味度总和
sum1
,然后用totalSum - sum1
计算下方的部分的美味度总和sum2
,并计算差值diff
,更新最小差值minDiff
。 - 垂直切割:遍历所有可能的垂直切割线(从第1列到第m-1列),计算切割线左侧的部分的美味度总和
sum1
,然后用totalSum - sum1
计算右侧的部分的美味度总和sum2
,并计算差值diff
,更新最小差值minDiff
。 - 返回结果:最终返回最小差值
minDiff
。
详细步骤
-
计算总和:
- 遍历整个二维数组,累加所有元素的值,得到
totalSum
。
- 遍历整个二维数组,累加所有元素的值,得到
-
水平切割:
- 对于每一行
i
(从1到n-1),计算切割线上方的部分的美味度总和sum1
。 - 计算切割线下方的部分的美味度总和
sum2
,即totalSum - sum1
。 - 计算差值
diff
,即|sum1 - sum2|
。 - 更新最小差值
minDiff
。
- 对于每一行
-
垂直切割:
- 对于每一列
j
(从1到m-1),计算切割线左侧的部分的美味度总和sum1
。 - 计算切割线右侧的部分的美味度总和
sum2
,即totalSum - sum1
。 - 计算差值
diff
,即|sum1 - sum2|
。 - 更新最小差值
minDiff
。
- 对于每一列
-
返回结果:
- 返回
minDiff
,即美味度差的最小值。
- 返回
solution完整代码
// 计算整个蛋糕的美味度总和
int totalSum = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
totalSum += a[i][j];
}
}
int minDiff = Integer.MAX_VALUE;
// 尝试所有水平切割线
for (int i = 1; i < n; i++) {
int sum1 = 0;
for (int row = 0; row < i; row++) {
for (int col = 0; col < m; col++) {
sum1 += a[row][col];
}
}
int sum2 = totalSum - sum1;
int diff = Math.abs(sum1 - sum2);
minDiff = Math.min(minDiff, diff);
}
// 尝试所有垂直切割线
for (int j = 1; j < m; j++) {
int sum1 = 0;
for (int col = 0; col < j; col++) {
for (int row = 0; row < n; row++) {
sum1 += a[row][col];
}
}
int sum2 = totalSum - sum1;
int diff = Math.abs(sum1 - sum2);
minDiff = Math.min(minDiff, diff);
}
return minDiff;