NO.64十六届蓝桥杯备战|基础算法-简单贪心|货仓选址|最大子段和|纪念品分组|排座椅|矩阵消除(C++)
贪⼼算法是两极分化很严重的算法。简单的问题会让你觉得理所应当,难⼀点的问题会让你怀疑⼈⽣
什么是贪⼼算法?
贪⼼算法,或者说是贪⼼策略:企图⽤局部最优找出全局最优。
- 把解决问题的过程分成若⼲步;
- 解决每⼀步时,都选择"当前看起来最优的"解法;
- "希望"得到全局的最优解。
贪⼼算法的特点
- 对于⼤多数题⽬,贪⼼策略的提出并不是很难,难的是证明它是正确的。因为贪⼼算法相较于暴⼒枚举,每⼀步并不是把所有情况都考虑进去,⽽是只考虑当前看起来最优的情况。但是,局部最优并不等于全局最优,所以我们必须要能严谨的证明我们的贪⼼策略是正确的。
⼀般证明策略有:反证法,数学归纳法,交换论证法等等。 - 当问题的场景不同时,贪⼼的策略也会不同。因此,贪⼼策略的提出是没有固定的套路和模板的。我们后⾯讲的题⽬虽然分类,但是⼤家会发现具体的策略还是相差很⼤。因此,不要妄想做⼏道贪⼼题⽬就能遇到⼀个会⼀个。有可能做完50道贪⼼题⽬之后,第51道还是没有任何思路。
如何学习贪⼼?
先有⼀个认知:做了⼏⼗道贪⼼的题⽬,遇到⼀个新的⼜没有思路,这时很正常的现象,把⼼态放平。
- 前期学习的时候,重点放在各种各样的策略上,把各种策略当成经验来吸收;
- 在平常学习的时候,我们尽可能的证明⼀下这个贪⼼策略是否正确,这样有利于培养我们严谨的思维。但是在⽐赛中,能想出来⼀个策略就已经不错了,如果再花费⼤量的时间去证明,有点得不偿失。这个时候,如果根据贪⼼策略想出来的若⼲个边界情况都能过的话,就可以尝试去写代码了。
P10452 货仓选址 - 洛谷
将所有的商店按照「从⼩到⼤」的顺序「排序」,把货仓建在中位数处,可以使得货仓到每家商店的距离之和最⼩:
- 如果n是奇数,货仓建在
a[(n + 1)/2]位置处; - 如果n是偶数,货仓建在
a[n/2] ∼ a[n/2 + 1]之间都是可以的
#include <bits/stdc++.h>
using namespace std;typedef long long LL;const int N = 1e5+10;int n;
int a[N];int main()
{ios::sync_with_stdio(false);cin.tie(0);cin >> n;for (int i = 1; i <= n; i++) cin >> a[i];sort(a+1, a+1+n);LL ret = 0;for (int i = 1; i <= n; i++){//中间位置的下标是(1+n)/2ret += abs(a[i] - a[(1+n) / 2]);}cout << ret << endl;return 0;
}
∣ a − x ∣ + ∣ b − x ∣ ≥ ∣ a − b ∣ |a-x|+|b-x| \ge |a-b| ∣a−x∣+∣b−x∣≥∣a−b∣
![![[Pasted image 20250404104208.png]]](https://i-blog.csdnimg.cn/direct/68c178bf44114bb989e529e409221747.png)
当x处于两者的中间位置时,左式取得最小值
形如:
s u m = ∑ i = 1 n ∣ a [ i ] − x ∣ = ∣ a [ 1 ] − x ∣ + ∣ a [ 2 ] − x ∣ + ⋯ + ∣ a [ n ] − x ∣ sum = \sum^{n}_{i=1}|a[i]-x|=|a[1]-x|+|a[2]-x|+\dots+|a[n]-x| sum=i=1∑n∣a[i]−x∣=∣a[1]−x∣+∣a[2]−x∣+⋯+∣a[n]−x∣
- 当x 取到n 个数的中位数时,和最⼩;
- 最⼩和为:
( a [ n ] − a [ 1 ] ) + ( a [ n − 1 ] − a [ 2 ] ) + . . . + ( a [ n + 1 − n / 2 ] − a [ n / 2 ] ) (a[n] - a[1]) + (a[n - 1] - a[2]) + ... + (a[n + 1 - n/2] - a[n/2]) (a[n]−a[1])+(a[n−1]−a[2])+...+(a[n+1−n/2]−a[n/2])
#include <bits/stdc++.h>
using namespace std;typedef long long LL;const int N = 1e5+10;int n;
int a[N];int main()
{ios::sync_with_stdio(false);cin.tie(0);cin >> n;for (int i = 1; i <= n; i++) cin >> a[i];sort(a+1, a+1+n);LL ret = 0;for (int i = 1; i <= n/2; i++){ret += abs(a[i] - a[n+1-i]); }cout << ret << endl;return 0;
}
P1115 最大子段和 - 洛谷
贪⼼想法:从前往后累加,我们会遇到下⾯两种情况:
- ⽬前的累加和>=0:那么当前累加和还会对后续的累加和做出贡献,那我们就继续向后累加,然后更新结果;
- ⽬前的累加和<0:对后续的累加和做不了⼀点贡献,直接⼤胆舍弃计算过的这⼀段,把累加和重置为0,然后继续向后累加。
这样我们在扫描整个数组⼀遍之后,就能更新出最⼤⼦段和。
![![[Pasted image 20250404143727.png]]](https://i-blog.csdnimg.cn/direct/a7c2bd159e3c48d68588e645e1e46ab5.png)
在累加的过程中算出⼀段区间和sum[a,b]<0 ,如果不舍弃这⼀段,那么[a,b]段之间就会存在⼀点,「以某个位置为起点」就会「更优」,分为下⾯两种情况
- 在ab段存在⼀个点c ,从这个位置开始,「越过b 」的累加和⽐从a 开始的累加和更优:
⽤「反证法」证明这种情况不存在。
如果存在这⼀点,那么:sum[c, b] > sum[a, b],这样才能保证向后加的时候更优。
但这是「不可能」的。如果sum[c, b] > sum[a, b],那么sum[a, c-1]<0,这与我们的贪⼼策略⽭盾。
因为我们贪⼼策略向后加的时候,只要不⼩于0,就会⼀直加下去。如果[a, c-1]段⼩于0,就
会在c点之前停⽌,不会累加到b。
因此区间内不存在⼀点,在计算⼦数组和时,在「越过b 」的情况下,能⽐从a 开始更优。 - 在ab段存在⼀个点c ,从这个位置开始,「不越过b 」的累加和⽐从a 开始的累加和更优:
也可以⽤「反证法」证明这种情况不存在。
如果存在这⼀点,那么:sum[c, k] > sum[a, k]。
但这是不可能的。如果sum[c, k] > sum[a, k],那么sum[a, c - 1] < 0,这与我们的贪⼼策略⽭盾。
因此区间内不存在⼀点,在计算⼦数组和时,在「不越过b 」的情况下,能⽐从a 开始更优。
综上所述,我们可以⼤胆舍弃这⼀段,重新开始。
#include <bits/stdc++.h>
using namespace std;const int N = 2e5 + 10;typedef long long LL;int n;
LL a[N];int main()
{ios::sync_with_stdio(false);cin.tie(0);cin >> n;for (int i = 1; i <= n; i++) cin >> a[i];LL sum = 0, ret = -1e6;for (int i = 1; i <= n; i++){sum += a[i];ret = max(ret, sum);if (sum < 0) sum = 0;}cout << ret << endl;return 0;
}
P1094 [NOIP 2007 普及组] 纪念品分组 - 洛谷
先将所有的纪念品排序,每次拿出当前的最⼩值x 与最⼤值y :
- 如果x + y ≤ w :就把这两个放在⼀起;
- 如果x + y > w:说明此时最⼤的和谁都凑不到⼀起,y单独分组,x继续留下在进⾏下⼀次判断。
直到所有的物品都按照上述规则分配之后,得到的组数就是最优解
可以⽤「交换论证法」证明贪⼼解就是最优解:
对于区间[ai......aj],如果存在最优解,但是ai与aj的分配⽅式与我们贪⼼解的分配⽅式不⼀样,那么就会有以下⼏种情况:
- 当
a[i] + a[j] > w时:
- 贪⼼解会把
a[j]单独分组,a[i]留待下次考虑; - 最优解也必定会把
a[j]单独分组,因为没有更⼩的值与a[j]组合。
此时贪⼼解与最优解⼀致。
- 当
a[i] + a[j] ≤ w时:
- 贪⼼解会把两者组合分在⼀个组⾥⾯;
- 最优解可能有以下⼏种情况:
a[j]单独⼀组:- 如果
a[i]也单独⼀组的话,最优解还不如贪⼼解分的组少,⽭盾; - 如果
a[i]和另⼀个a[k]⼀组的话,我们可以把a[k]与a[j]交换,此时并不影响结果,和贪⼼解⼀致。
- 如果
a[j]和a[k]⼀组:- 如果
a[i]单独⼀组的话,交换a[i]和a[k],此时并不影响最终结果,和贪⼼解⼀致; - 如果
a[i]和a[l]⼀组的话,交换a[i]和a[k],此时变成(a[i]+a[j]),(a[l]+a[k]),其中a[l]+a[k]<=a[j]+a[k]<=w,不影响最终结果,和贪⼼解⼀致。
综上所述,我们可以通过不断的「调整」,使的最优解在「不改变其最优性」的前提下,变得和贪⼼解⼀致。那我们的贪⼼策略就等价于最优策略。
- 如果
#include <bits/stdc++.h>
using namespace std;const int N = 3e4 + 10;int w, n;
int a[N];int main()
{ios::sync_with_stdio(false);cin.tie(0);cin >> w >> n;for (int i = 1; i <= n; i++) cin >> a[i];sort(a+1, a+1+n);int l = 1, r = n, ret = 0;while (l <= r){if(a[l] + a[r] <= w) l++, r--;else r--;ret++;}cout << ret << endl;return 0;
}
P1056 [NOIP 2008 普及组] 排座椅 - 洛谷
由题意可得,我们会发现⼀些性质:
- 设置横向通道的时候,并「不影响」左右相邻的同学;
- 设置纵向通道的时候,并「不影响」上下相邻的同学。
因此我们可以「分开」处理横向通道和纵向通道。
处理横向通道(纵向同理,就不多赘述): - 收集每⼀⾏如果放上通道之后,会解决多少个交头接⽿的同学;
- 对收集的信息「从⼤到⼩」排序,选最⼤的k ⾏就是最优结果。
#include <bits/stdc++.h>
using namespace std;const int N = 1010;struct node
{int index;int cnt;
}row[N], col[N];int m, n, k, l, d;//按cnt从大到小
bool cmp1(node& x, node& y)
{return x.cnt > y.cnt;
}
//按index从小到大
bool cmp2(node& x, node& y)
{return x.index < y.index;
}int main()
{ios::sync_with_stdio(false);cin.tie(0);cin >> m >> n >> k >> l >> d;//初始化结构体数组for (int i = 1; i <= m; i++) row[i].index = i;for (int i = 1; i <= n; i++) col[i].index = i;while(d--){int x, y, p, q; cin >> x >> y >> p >> q;if (x == p) col[min(y, q)].cnt++;else row[min(x, p)].cnt++;}//对两个数组按照cnt从大到小排序sort(row+1, row+1+m, cmp1);sort(col+1, col+1+n, cmp1);//对row数组,前k个元素,按照下标从小到大排序sort(row+1, row+1+k, cmp2);//对col数组,前l个元素,按照下标从小到大排序sort(col+1, col+1+l, cmp2);for (int i = 1; i <= k; i++){cout << row[i].index << " ";}cout << endl;for (int i = 1; i <= l; i++){cout << col[i].index << " ";}cout << endl;return 0;
}
矩阵消除游戏
最优解是先暴⼒枚举所有⾏的选法,在⾏的选择都确定之后,再去贪⼼的处理列
#include <bits/stdc++.h>
using namespace std;const int N = 20;int n, m, k;
int a[N][N];
int col[N]; //统计列和//统计x的二进制中1的个数
int calc(int x)
{int ret = 0;while (x){ret++;x -= x & -x;}return ret;
}//从大到小排序
bool cmp(int a, int b)
{return a > b;
}int main()
{ios::sync_with_stdio(false);cin.tie(0);cin >> n >> m >> k;for (int i = 0; i < n; i++)for (int j = 0; j < m; j++)cin >> a[i][j];int ret = 0;//暴力枚举行所有选法for (int st = 0; st < (1 << n); st++){int cnt = calc(st);if (cnt > k) continue; //不合法memset(col, 0, sizeof col);int sum = 0; //记录当前选法的和for (int i = 0; i < n; i++){for (int j = 0; j < m; j++){if ((st >> i) & 1) sum += a[i][j];else col[j] += a[i][j];}}//处理列sort(col, col + m, cmp);//选k - cnt列for (int j = 0; j < min(k - cnt, m); j++) sum += col[j];ret = max(ret, sum);}cout << ret << endl;return 0;
}
相关文章:
NO.64十六届蓝桥杯备战|基础算法-简单贪心|货仓选址|最大子段和|纪念品分组|排座椅|矩阵消除(C++)
贪⼼算法是两极分化很严重的算法。简单的问题会让你觉得理所应当,难⼀点的问题会让你怀疑⼈⽣ 什么是贪⼼算法? 贪⼼算法,或者说是贪⼼策略:企图⽤局部最优找出全局最优。 把解决问题的过程分成若⼲步;解决每⼀步时…...
瑞萨RA4M2使用心得-KEIL5的第一次编译
目录 前言 环境: 开发板:RA-Eco-RA4M2-100PIN-V1.0 IDE:keil5.35 一、软件的下载 编辑瑞萨的芯片,除了keil5 外还需要一个软件:RASC 路径:Releases renesas/fsp (github.com) 向下找到: …...
java根据集合中对象的属性值大小生成排名
1:根据对象属性降序排列 public static <T extends Comparable<? super T>> LinkedHashMap<T, Integer> calculateRanking(List<ProductPerformanceInfoVO> dataList, Function<ProductPerformanceInfoVO, T> keyExtractor) {Linked…...
数据分析-Excel-学习笔记
Day1 复现报表聚合函数:日期联动快速定位区域SUMIF函数SUMIFS函数环比、同比计算IFERROR函数混合引用单元格格式总结汇报 拿到一个Excel表格,首先要看这个表格个构成(包含了哪些数据),几行几列,每一列的名称…...
整车CAN网络和CANoe
车载网络中主要包含有Can网络,Lin网络,FlexRay,Most,以太网。 500kbps:500波特率,表示的数据传输的速度。表示的是最大的网速传输速度。也就是每秒 500kb BodyCan车身Can InfoCan娱乐信息Can 车身CAN主要连接的是ESB电动安全带 ADB自适应远光灯等 PTCan动力Can 底盘Can...
ChatGPT 的新图像生成器非常擅长伪造收据
本月,ChatGPT 推出了一种新的图像生成器,作为其 4o 模型的一部分,该模型在生成图像内的文本方面做得更好。 人们已经在利用它来生成假的餐厅收据,这可能会为欺诈者使用的已经很广泛的 AI 深度伪造工具包添加另一种工具。 多产的…...
JS页面尺寸事件
元素位置 在这里插入图片描述 父元素带有定位时输出相对于父亲元素的距离值...
SpringBoot的日志框架
目录 默认日志框架 日志配置 更换日志框架 排除默认Logback 引入目标日志框架 添加配置文件 logback.xml SpringBoot的核心设计宗旨是约定大于配置,很多框架功能都给你默认加载和配置完成供你使用,但这就要求使用者对框架有一定的理解和改造能力,比如这个日志框架,是其…...
网络协议之基础介绍
写在前面 本文看下网络协议相关基础内容。 1:为什么要有网络协议 为了实现世界各地的不同主机的互联互通。 2:协议的三要素 协议存在的目的就是立规矩,无规矩不成方圆嘛!但是这个规矩也不是想怎么立就怎么立的,也…...
【学Rust写CAD】34 精确 Alpha 混合函数(argb.rs补充方法)
源码 #[inline]pub fn over_exact(self, dst: Argb) -> Argb {let a 255 - self.alpha32();let t dst.rb() * a 0x80_00_80;let mut rb (t ((t >> 8) & Argb::MASK)) >> 8;rb & Argb::MASK;rb self.rb();// saturaterb | 0x1000100 - ((rb >&…...
利用NumPy核心知识点优化TensorFlow模型训练过程
利用NumPy核心知识点优化TensorFlow模型训练过程 NumPy是Python科学计算的基础库,掌握它的高效操作可以显著提升TensorFlow模型的训练效率。本文详细探讨如何将NumPy的核心优势应用于TensorFlow模型训练的各个环节。 1. 数据预处理优化 高效向量化操作 NumPy的向…...
初识数据结构——Java集合框架解析:List与ArrayList的完美结合
📚 Java集合框架解析:List与ArrayList的完美结合 🌟 前言:为什么我们需要List和ArrayList? 在日常开发中,我们经常需要处理一组数据。想象一下,如果你要管理一个班级的学生名单,或…...
TDengine 从入门到精通(2万字长文)
目录 第一章:走进 TDengine 的世界 TDengine 是个啥? TDengine 的硬核特性 性能炸裂 分布式架构,天生可扩展 SQL 用起来贼顺手 写入方式花样多 内置缓存,省心又省力 TDengine 能干啥? 智能制造 能源管理 物联网平台 工业大数据 第二章:上手 TDengine:安装与…...
DevOps 与持续集成(CI/CD)
1. DevOps 概述 DevOps(Development + Operations)是一种软件开发方法,强调开发(Dev)与运维(Ops)协作,通过自动化工具提高软件交付效率。其目标是: ✅ 提高部署速度 —— 频繁发布新版本 ✅ 减少人为错误 —— 通过自动化降低运维风险 ✅ 增强可观测性 —— 监控和日…...
[特殊字符] 使用 Handsontable 构建一个支持 Excel 公式计算的动态表格
在 Web 应用中,处理表格数据并提供 Excel 级的功能(如公式计算、数据导入导出)一直是个挑战。今天,我将带你使用 React Handsontable 搭建一个强大的 Excel 风格表格,支持 公式计算、Excel 文件导入导出,并…...
uniapp微信小程序引入vant组件库
1、首先要有uniapp项目,根据vant官方文档使用yarn或npm安装依赖: 1、 yarn init 或 npm init2、 # 通过 npm 安装npm i vant/weapp -S --production# 通过 yarn 安装yarn add vant/weapp --production# 安装 0.x 版本npm i vant-weapp -S --production …...
贪心进阶学习笔记
反悔贪心 贪心是指直接选择局部最优解,不需要考虑之后的影响。 而反悔贪心是在贪心上面加了一个“反悔”的操作,于是又可以撤销之前的“鲁莽行动”,让整个的选择稍微变得“理智一些”。 于是,我个人理解,反悔贪心是…...
Java 大视界 -- Java 大数据在航天遥测数据分析中的技术突破与应用(177)
💖亲爱的朋友们,热烈欢迎来到 青云交的博客!能与诸位在此相逢,我倍感荣幸。在这飞速更迭的时代,我们都渴望一方心灵净土,而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识,也…...
架构师面试(二十七):单链表
问题 今天的问题对于架构师来说会相对容易许多。今天出一个【数据结构与算法】相关的题目,醒醒脑。 给一张【单链表】,该单链表有100个节点元素(当然,事先我们是不知道100这个数目的),要获取倒数第8个元素…...
从扩展黎曼泽塔函数构造物质和时空的结构-15
回来考虑泽塔函数, 我们知道, 也就是在平面直角坐标系上反正切函数在x上的变化率,那么不难看出, 就是在s维空间上的“广义”反正切函数在单位p上的变化率,而泽塔函数,就是这些变化率的全乘积, 因…...
数据库访问工具 dbVisitor v6.0.0 发布
dbVisitor 是一款轻量小巧、功能完备的 Java 数据库 ORM 工具,它的前身是 HasorDB,历经 8 年迭代后正式更名为 dbVisitor 并开始独立发展4。以下是关于 dbVisitor v6.0.0 发布的相关信息: 发布说明 在 Maven Central 上可查询到 dbVisitor …...
01背包问题详解 具体样例模拟版
01背包 有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。 第 i 件物品的体积是 v i v_i vi,价值是 w i w_i wi。 求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。 输出最大价值。 输入格式 …...
网络初识 - Java
网络发展史: 单机时代(独立模式) -> 局域网时代 -> 广域网时代 -> 移动互联网时代 网络互联:将多台计算机链接再一起,完成数据共享。 数据共享的本质是网络数据传输,即计算机之间通过网络来传输数…...
zk基础—5.Curator的使用与剖析一
大纲 1.基于Curator进行基本的zk数据操作 2.基于Curator实现集群元数据管理 3.基于Curator实现HA主备自动切换 4.基于Curator实现Leader选举 5.基于Curator实现分布式Barrier 6.基于Curator实现分布式计数器 7.基于Curator实现zk的节点和子节点监听机制 8.基于Curator创…...
大模型快速 ASGI 服务器uvicorn
基础概念类 1. 什么是 Uvicorn,它的作用是什么? 答案:Uvicorn 是一个基于 Python 的快速 ASGI(异步服务器网关接口)服务器。它的主要作用是作为 Web 应用程序的服务器,负责接收客户端的请求,并…...
每日一题(小白)回溯篇4
深度优先搜索题:找到最长的路径,计算这样的路径有多少条(使用回溯) 分析题意可以得知,每次向前后左右走一步,直至走完16步就算一条走通路径。要求条件是不能超出4*4的范围,不能重复之前的路径。…...
消息队列基础概念及选型,常见解决方案包括消息可靠性、消息有序、消息堆积、重复消费、事务消息
前言 是时候总结下消息队列相关知识点啦!我搓搓搓搓 本文包括消息队列基础概念介绍,常见解决方案包括消息可靠性、消息有序、消息堆积、重复消费、事务消息 参考资料: Kafka常见问题总结 | JavaGuide RocketMQ常见问题总结 | JavaGuide …...
基于STM32与应变片的协作机械臂力反馈控制系统设计与实现---3.3 机械结构改装
3.3 机械臂结构改装设计与实施 一、改装需求分析 1.1 改装类型分级 改装级别涉及范围典型改动周期成本I级(小型)末端执行器工具快换装置1-3天$500-2000II级(中型)关节模块电机/减速器升级1-2周$2000-8000III级(大型)本体结构材质/拓扑优化1-3月$8000+1.2 关键参数变更评…...
k8s进阶之路:本地集群环境搭建
概述 文章将带领大家搭建一个 master 节点,两个 node 节点的 k8s 集群,容器基于 docker,k8s 版本 v1.32。 一、系统安装 安装之前请大家使用虚拟机将 ubuntu24.04 系统安装完毕,我是基于 mac m1 的系统进行安装的,所…...
云服务器实战:用 Nginx 搭建高性能 API 网关与反向代理服务(附完整配置流程)
在如今的 Web 系统架构中,“接口统一出口”已成为必备设计模式——无论是前后端分离、微服务架构,还是多端接入(Web、小程序、App),一个稳定、高性能、可扩展的 API 网关至关重要。 而 Nginx,作为轻量级高…...
