当前位置: 首页 > news >正文

07 开发商购买土地 数组 (前缀和)

\44. 开发商购买土地(第五期模拟笔试)

题目描述

在一个城市区域内,被划分成了n * m个连续的区块,每个区块都拥有不同的权值,代表着其土地价值。目前,有两家开发公司,A 公司和 B 公司,希望购买这个城市区域的土地。

现在,需要将这个城市区域的所有区块分配给 A 公司和 B 公司。

然而,由于城市规划的限制,只允许将区域按横向或纵向划分成两个子区域,而且每个子区域都必须包含一个或多个区块。 为了确保公平竞争,你需要找到一种分配方式,使得 A 公司和 B 公司各自的子区域内的土地总价值之差最小。

注意:区块不可再分。

输入描述

第一行输入两个正整数,代表 n 和 m。

接下来的 n 行,每行输出 m 个正整数。

输出描述

请输出一个整数,代表两个子区域内土地总价值之间的最小差距。

输入示例
3 3
1 2 3
2 1 3
1 2 3
输出示例
0
提示信息

如果将区域按照如下方式划分:

1 2 | 3
2 1 | 3
1 2 | 3

两个子区域内土地总价值之间的最小差距可以达到 0。

数据范围:

1 <= n, m <= 100;
n 和 m 不同时为 1。


//前缀和
#include <iostream>
#include <vector>
#include <climits>using namespace std;
int main () {int n, m;cin >> n >> m;int sum = 0;vector<vector<int>> vec(n, vector<int>(m, 0)) ;for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {cin >> vec[i][j];sum += vec[i][j];}}// 统计横向vector<int> horizontal(n, 0);for (int i = 0; i < n; i++) {for (int j = 0 ; j < m; j++) {horizontal[i] += vec[i][j];}}// 统计纵向vector<int> vertical(m , 0);for (int j = 0; j < m; j++) {for (int i = 0 ; i < n; i++) {vertical[j] += vec[i][j];}}// 横着切一刀,试所有切法,找差值最小的!int result = INT_MAX;int horizontalCut = 0;//记录切完后,上面那部分的总和。for (int i = 0 ; i < n; i++) {//尝试所有切的位置!horizontalCut += horizontal[i];//把第 i 行加进来,代表切到第 i 行下面。// 上面总和是 cut,下面总和是 sum - cut,差值 = cut - (sum - cut) = sum - 2*cutresult = min(result, abs(sum - horizontalCut - horizontalCut));}//竖着切一刀,试所有切法,找差值最小的!int verticalCut = 0;for (int j = 0; j < m; j++) {verticalCut += vertical[j];result = min(result, abs(sum - verticalCut - verticalCut));}cout << result << endl;
}
  • 看到本题,大家如果想暴力求解,应该是 n^3 的时间复杂度,

    一个 for 枚举分割线, 嵌套 两个for 去累加区间里的和。

    如果本题要求 任何两个行(或者列)之间的数值总和,大家在0058.区间和 的基础上 应该知道怎么求。

    就是前缀和的思路,先统计好,前n行的和 q[n],如果要求矩阵 a行 到 b行 之间的总和,那么就 q[b] - q[a - 1]就好。

    至于为什么是 a - 1,大家去看 0058.区间和 的分析,使用 前缀和 要注意 区间左右边的开闭情况。

    本题也可以使用 前缀和的思路来求解,先将 行方向,和 列方向的和求出来,这样可以方便知道 划分的两个区间的和。


//暴力优化
#include <iostream>
#include <vector>
#include <climits>using namespace std;
int main () {int n, m;cin >> n >> m;int sum = 0;vector<vector<int>> vec(n, vector<int>(m, 0)) ;for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {cin >> vec[i][j];sum += vec[i][j];}}int result = INT_MAX;int count = 0; // 统计遍历过的行for (int i = 0; i < n; i++) {for (int j = 0 ; j < m; j++) {count += vec[i][j];// 遍历到行末尾时候开始统计if (j == m - 1) result = min (result, abs(sum - count - count));}}count = 0; // 统计遍历过的列for (int j = 0; j < m; j++) {for (int i = 0 ; i < n; i++) {count += vec[i][j];// 遍历到列末尾的时候开始统计if (i == n - 1) result = min (result, abs(sum - count - count));}}cout << result << endl;
}
  • 其实本题可以在暴力求解的基础上,优化一下,就不用前缀和了,在行向遍历的时候,遇到行末尾就统一一下, 在列向遍历的时候,遇到列末尾就统计一下。

    时间复杂度也是 O(n^2)

普通暴力思想,练习代码模拟水平

#include <iostream>
#include <vector>
#include <climits>   // 用于 INT_MAX
#include <cmath>     // 用于 abs() 绝对值
using namespace std;int main() {// 一、输入部分:读入矩阵的行数 n 和列数 mint n, m;cin >> n >> m;// 定义 n 行 m 列的二维数组(矩阵),存储土地价值vector<vector<int>> a(n, vector<int>(m));// 读入矩阵的每个数字for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {cin >> a[i][j];}}// 定义答案:最小差值// 先初始化为“无穷大”,后面不断更新成更小的int min_diff = INT_MAX;// ======================================================// 二、暴力枚举:所有【横着切一刀】的可能性// 思路:切在某一行下面,把矩阵分成 上半部分 + 下半部分// ======================================================// 循环:尝试每一个横向切割位置// cut 表示:切在第 cut 行的下面// 注意:不能切最后一行下面,否则下半部分为空,所以是 cut < n-1for (int cut = 0; cut < n - 1; cut++) {// 用来存储:切完后,【上半部分所有土地的总价值】int top_sum = 0;// 暴力累加:从上到下,把 0 ~ cut 行所有数字加起来for (int i = 0; i <= cut; i++) {for (int j = 0; j < m; j++) {top_sum += a[i][j];}}// 暴力计算:整个矩阵的总价值int total = 0;for (int i = 0; i < n; i++)for (int j = 0; j < m; j++)total += a[i][j];// 计算当前切法的差值:// 上半部分和 - 下半部分和 的绝对值// 下半部分和 = 总和 - 上半部分和int diff = abs(top_sum - (total - top_sum));// 更新最小差值:保留最小的那个min_diff = min(min_diff, diff);}// ======================================================// 三、暴力枚举:所有【竖着切一刀】的可能性// 思路:切在某一列右边,把矩阵分成 左半部分 + 右半部分// ======================================================// 循环:尝试每一个纵向切割位置// cut 表示:切在第 cut 列的右边// 同样不能切最后一列,所以 cut < m-1for (int cut = 0; cut < m - 1; cut++) {// 用来存储:切完后,【左半部分所有土地的总价值】int left_sum = 0;// 暴力累加:从左到右,把 0 ~ cut 列所有数字加起来for (int j = 0; j <= cut; j++) {for (int i = 0; i < n; i++) {left_sum += a[i][j];}}// 再次计算整个矩阵总和(暴力写法,不优化)int total = 0;for (int i = 0; i < n; i++)for (int j = 0; j < m; j++)total += a[i][j];// 计算当前切法的差值int diff = abs(left_sum - (total - left_sum));// 更新最小差值min_diff = min(min_diff, diff);}// 输出所有切法中,最小的差值cout << min_diff << endl;return 0;
}
http://www.jsqmd.com/news/699770/

相关文章:

  • MASA模组汉化终极指南:让Minecraft专业工具说中文
  • 【算法笔记】二分查找与二分答案
  • 解决DWPose预处理器ONNX运行时错误的深度技术分析与修复方案
  • 集团总部失控:诸侯是怎么养成的?
  • 为什么 Agent 框架越来越多:LangChain、LangGraph、AutoGen 生态对比
  • 【嵌入式调试新纪元】:VSCode 2026原生支持SWD over USB-C、内存映射热重载与双核同步断点(仅限首批127个MCU型号)
  • Cursor Pro激活器实战:3步高效破解AI编程助手限制
  • Materials Project API技术架构与高级应用指南:从数据查询到材料科学创新
  • stp思维导图
  • k1周:多模态融合-阿尔茨海默病检测
  • 剪映专业版教程:制作百叶窗转场效果
  • 从 Agent 到 Agentic AI:企业级智能体工程实现的关键差异
  • 显卡驱动彻底清理指南:Display Driver Uninstaller深度解析与实战应用
  • Docker 与 Kubernetes 部署最佳实践 2027
  • UnityFigmaBridge:打破设计与开发壁垒的终极协作解决方案
  • AI 伴侣的伦理困境:当代码学会说「我爱你」,人类准备好了吗?
  • 为什么92%的嵌入式团队在LLM移植中踩坑?:揭秘C语言指针对齐陷阱、中断上下文推理崩溃、Flash页擦写冲突三大“静默杀手”
  • AI Agent在体育与娱乐领域的应用:数据分析与体验优化
  • 如何快速解密Wii U游戏文件:CDecrypt工具完整指南 [特殊字符]
  • Python快速验证分类算法:scikit-learn实战指南
  • BilibiliDown:跨平台B站视频下载的完整解决方案
  • Claude-Code-Workflow:基于AI的智能研发工作流引擎实战解析
  • 嵌入式团队紧急升级预警:VSCode 2026.1起废弃legacy GDB adapter——3类老旧JTAG探针将彻底失联?
  • 卡梅德生物技术快报|哺乳动物细胞表达系统:载体优化、宿主选型与位点重组技术实现方案
  • 第5章:时间的相对性思辨
  • Windows上使用VS2026和CMake编译LearnOpenGL项目源代码
  • 深入解析 Ansible:从入门到实践
  • 如何快速搭建全平台直播弹幕抓取系统:终极实战指南
  • 解密ClickShow:Windows鼠标交互的视觉化革命
  • 2026攻防实战:如何利用AI工作流实现自动化WAF绕过与Payload变异?