中等题 小M的蛋糕切割问题
问题描述
小M有一个 的矩形蛋糕,蛋糕被分为 个区域,每个区域都有一个美味度。她希望通过一刀将蛋糕切成两部分,一部分自己吃,另一部分给小团。切下的区域必须是完整的,即不能把某个小正方形切成两个小区域。
小M希望两个人吃的部分的美味度之和尽量接近。你的任务是计算出美味度差的最小值,即 的最小值,其中 是小M吃到的美味度, 是小团吃到的美味度。
测试样例
样例1:
输入:n = 2, m = 3, a = [[1, 1, 4], [5, 1, 4]]
输出:0
样例2:
输入:n = 3, m = 3, a = [[3, 2, 1], [4, 5, 6], [7, 8, 9]]
输出:3
样例3:
输入:n = 2, m = 2, a = [[1, 2], [3, 4]]
输出:2
思考步骤
问题要求我们通过一刀将一个矩形蛋糕切成两部分,使得两部分的美味度之差最小。我们首先要明确以下几点:
- 矩形的切割方式:切割可以是水平的或垂直的,且切割必须沿着整行或整列进行,不能将某个小区域切成两部分。
- 美味度差最小化的目标:我们需要尽可能让两部分的美味度之和接近。设两部分的美味度分别为 和 ,目标是最小化 。
关键点分析
-
矩阵的分割方式:由于切割是整行整列进行的,我们可以考虑两种切割方式:
- 水平切割:切成两部分时,可以选择将矩阵切割成两部分,上面部分的行数是 (其中 ),下面部分则是剩余的行。
- 垂直切割:切割时可以选择将矩阵切割成两部分,左边部分的列数是 (其中 ),右边部分则是剩余的列。
-
美味度的计算:在任意一刀切割的情况下,两个部分的美味度总和 是固定的。通过计算所有区域的总美味度 ,我们可以通过计算其中一部分的美味度 ,然后通过公式 来得到另一部分的美味度。
-
减小美味度差:目标是使得 最小。为了优化计算,我们可以通过对每行或每列前缀和的处理,快速计算切割后任意部分的美味度总和。
步骤分析
- 计算总美味度:首先计算整个矩阵的美味度总和 。
- 计算前缀和:可以通过计算行或列的前缀和来快速计算任意部分的美味度。对于每一行或每一列,通过前缀和能够快速得到切割后某部分的美味度。
- 比较所有可能的切割方式:遍历所有可能的切割方式,计算美味度差 ,并找到最小的差值。
代码实现
def solution(n, m, a):
total_sum = sum(sum(row) for row in a) # 计算整个矩阵的美味度总和
min_diff = float('inf') # 初始化最小差值为无穷大
# 水平切割
row_prefix_sum = [0] * (n + 1) # 记录行前缀和
for i in range(1, n + 1):
row_prefix_sum[i] = row_prefix_sum[i - 1] + sum(a[i - 1])
for i in range(1, n):
s1 = row_prefix_sum[i]
s2 = total_sum - s1
min_diff = min(min_diff, abs(s1 - s2))
# 垂直切割
col_prefix_sum = [0] * (m + 1) # 记录列前缀和
for j in range(1, m + 1):
col_prefix_sum[j] = col_prefix_sum[j - 1] + sum(a[i][j - 1] for i in range(n))
for j in range(1, m):
s1 = col_prefix_sum[j]
s2 = total_sum - s1
min_diff = min(min_diff, abs(s1 - s2))
return min_diff