青训营X豆包MarsCode技术训练营|豆包MarsCode AI刷题

43 阅读3分钟

中等题 小M的蛋糕切割问题

问题描述

小M有一个 n×mn \times m 的矩形蛋糕,蛋糕被分为 n×mn \times m 个区域,每个区域都有一个美味度。她希望通过一刀将蛋糕切成两部分,一部分自己吃,另一部分给小团。切下的区域必须是完整的,即不能把某个小正方形切成两个小区域。

小M希望两个人吃的部分的美味度之和尽量接近。你的任务是计算出美味度差的最小值,即 s1s2|s_1 - s_2| 的最小值,其中 s1s_1 是小M吃到的美味度,s2s_2 是小团吃到的美味度。


测试样例

样例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

思考步骤

问题要求我们通过一刀将一个矩形蛋糕切成两部分,使得两部分的美味度之差最小。我们首先要明确以下几点:

  1. 矩形的切割方式:切割可以是水平的或垂直的,且切割必须沿着整行或整列进行,不能将某个小区域切成两部分。
  2. 美味度差最小化的目标:我们需要尽可能让两部分的美味度之和接近。设两部分的美味度分别为 s1s_1s2s_2,目标是最小化 s1s2|s_1 - s_2|

关键点分析

  1. 矩阵的分割方式:由于切割是整行整列进行的,我们可以考虑两种切割方式:

    • 水平切割:切成两部分时,可以选择将矩阵切割成两部分,上面部分的行数是 ii(其中 1i<n1 \leq i < n),下面部分则是剩余的行。
    • 垂直切割:切割时可以选择将矩阵切割成两部分,左边部分的列数是 jj(其中 1j<m1 \leq j < m),右边部分则是剩余的列。
  2. 美味度的计算:在任意一刀切割的情况下,两个部分的美味度总和 SS 是固定的。通过计算所有区域的总美味度 total_sum\text{total\_sum},我们可以通过计算其中一部分的美味度 s1s_1,然后通过公式 s2=total_sums1s_2 = \text{total\_sum} - s_1 来得到另一部分的美味度。

  3. 减小美味度差:目标是使得 s1s2|s_1 - s_2| 最小。为了优化计算,我们可以通过对每行或每列前缀和的处理,快速计算切割后任意部分的美味度总和。

步骤分析

  1. 计算总美味度:首先计算整个矩阵的美味度总和 total_sum\text{total\_sum}
  2. 计算前缀和:可以通过计算行或列的前缀和来快速计算任意部分的美味度。对于每一行或每一列,通过前缀和能够快速得到切割后某部分的美味度。
  3. 比较所有可能的切割方式:遍历所有可能的切割方式,计算美味度差 s1s2|s_1 - s_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