小M的蛋糕切割问题

问题描述

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

小M希望两个人吃的部分的美味度之和尽量接近。你的任务是计算出美味度差的最小值,即 ∣s1−s2∣∣s1​−s2​∣ 的最小值,其中 s1s1​ 是小M吃到的美味度,s2s2​ 是小团吃到的美味度。


测试样例

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

问题理解

需要将一个 n x m 的矩形蛋糕切成两部分,使得两部分的美味度之和尽量接近。美味度之和的差值需要最小化。

数据结构选择

  1. 二维数组:用于存储蛋糕的美味度。
  2. 前缀和数组:用于快速计算任意子矩阵的美味度之和。

算法步骤

  1. 计算前缀和:首先计算一个二维前缀和数组 prefixSum,其中 prefixSum[i][j] 表示从 (0,0) 到 (i,j) 的子矩阵的美味度之和。
  2. 枚举切割线
    • 水平切割:枚举每一行作为切割线,计算上下两部分的美味度之和。
    • 垂直切割:枚举每一列作为切割线,计算左右两部分的美味度之和。
  3. 计算差值:对于每一种切割方式,计算两部分的美味度之和的差值,并记录最小差值。

 代码实现:

#include <iostream>
#include <vector>
#include <climits>
using namespace std;

int solution(int n, int m, vector<vector<int>> a) {
    // 计算前缀和数组
    vector<vector<int>> prefixSum(n + 1, vector<int>(m + 1, 0));
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            prefixSum[i][j] = a[i-1][j-1] + prefixSum[i-1][j] + prefixSum[i][j-1] - prefixSum[i-1][j-1];
        }
    }

    int minDiff = INT_MAX;

    // 枚举水平切割线
    for (int i = 1; i < n; ++i) {
        int sum1 = prefixSum[i][m];
        int sum2 = prefixSum[n][m] - sum1;
        minDiff = min(minDiff, abs(sum1 - sum2));
    }

    // 枚举垂直切割线
    for (int j = 1; j < m; ++j) {
        int sum1 = prefixSum[n][j];
        int sum2 = prefixSum[n][m] - sum1;
        minDiff = min(minDiff, abs(sum1 - sum2));
    }

    return minDiff;
}

int main() {
    cout << (solution(2, 3, {{1, 1, 4}, {5, 1, 4}}) == 0) << endl;
    cout << (solution(3, 3, {{3, 2, 1}, {4, 5, 6}, {7, 8, 9}}) == 3) << endl;
    cout << (solution(2, 2, {{1, 2}, {3, 4}}) == 2) << endl;

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值