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

【算法小讲堂】#1 贪心算法

引入——关于贪心算法

我们先来做一个小游戏——现在假设自己是一个小偷,桌上有一些物品,包括一台iPhone15、一个充电宝、一个眼罩和一个溜溜梅。此时,你听说警察即将到来,那么你会先带走哪个东西呢?

一般来讲,时间一定的话,我们通常会先拿走桌面上最贵的物品

“先拿最贵的走”,这种思想就是贪心

贪心算法解决的问题大致如此——

【从大集合中选出东西】

  • 排序
  • 按顺序选

如此,收益最大。


可是,为什么每次选“最贵的”,最终收益就是最大的?

这并不明显。

很多时候,贪心算法需要严格方式证明,在不同的情景下。


示例——排队接水问题

n n n个同学排队接水,接水的时间分别是 t 1 t1 t1 t 2 t2 t2 t 3 t3 t3 t 4 t4 t4 t 5 t5 t5,…, t n tn tn

  • 如何安排同学接水的顺序?
  • 使得平均接水时间最短。
  • 并计算出最短的平均接水时间。

分析——特例假想

假设这 n n n名同学打水的时间普遍较短,除了其中的同学小明,他拿了一个水塘大(夸张)的盆来打水。

此刻,如果让他站在队伍的最前面,其他同学等待时间是不是就非常非常久了,我们的平均等待时间想必就非常大了。

因此,合理的安排是——

让打水快的同学尽可能站在队伍前面。

模型——解决问题的一般方法

我们需要按一定的步骤解决此类问题,一般来讲,第一步是排序,明白什么样的同学应该排在前面;第二步是选择,模拟此过程计算出平均接水时间

A 排序

找到符合贪心思想的排序方案——打水快的排前面。

B 选择

依次序进行选择,模拟目标过程计算所需答案。

补充 数学证明

这种符合直觉的贪心方法未必能够经得起数学的推敲。为了保证做法的正确,我们通常还要建立数学模型,利用数学手段证明这一解决问题的方法是行之有效的。


贪心算法的问题中,常见地需要使用到诸如排序不等式的数学公式。请添加图片描述


一些尝试——加上一些限制条件

在一开始,我们假设了一个情境。

此时我们希望加入再一些限制条件,使得其更符合现实生活——

  • 背包的容量是有限的
  • 每一样物品是既有重量又有价值的

倘若这样,那么我们就不仅仅需要考虑物品的价值

因为向背包装入最贵的东西后,可能再也没用地方装下其余同样有很高价值但重量小的物品了。

请添加图片描述

此类问题成为了相对复杂一些的01背包问题。


现实生活中,还可能有以下情形——

由于警察并不一定往往在最后赶到,实际应该是在不同时刻赶到的概率是不相同的。

此时,我们需要利用动态规划解决,以求得最大的数学期望


再看冒泡排序——排序的贪心本质

请添加图片描述

先假定一个情形——你拿到一堆标着数字的卡片(可能有100张),你需要做的是给卡片按数字从小到大的顺序进行排序

你本能会做的是先铺开这些卡片,整体上看看这些数字大小。

当你的眼睛落在任意两张不同数字的卡片上,会有这样的情况——

(左边的卡片是 N 1 N1 N1,右边的卡片是 N 2 N2 N2

目标的情形是 N 1 < N 2 N1<N2 N1<N2,所以如果左边的数字大于右边的数字,我们尝试交换

显然,这种做法没有什么条理。但是可以确信的是——

在每一次操作后,我们都更加接近那个正确的答案。

而经过有限次操作后,就一定能够得到最优解,即正确的排序。

冒泡排序,其实就是按照一定的规律执行判断-交换的步骤。

思想的本质依旧是贪心


贪心的局部探索——动态规划

请添加图片描述

一个思考问题:给出一个山的三维模型(图片见上),目标求得此山中的最低点。

假设你是一位在这个山中迷路的攀登者,而山里起了大雾,你需要尽快到山的低洼处修整。你只能知道你所站的地方的坡度,没有其余办法找到那个低洼处

此时,为找到低洼处,我们会做的一定是一直向**“下”走,即一直下坡,直到不能再下坡**。

最终找到的未必是最低点,寻找的过程中很有可能一步就走到了再也回不去的道路(指远离最优解),但是我们知道,至少这样,让我们错误的概率更小一些。因为哪怕这个点不是全局中的最优解,它也会是我在这个区域能够找到的最好的解

这个试探的过程,我们称之为局部搜索


贪心算法的问题实例

🟢 [NOIP1998 提高组] 拼数

比较传统的贪心问题,解决问题的关键在于比较和交换相邻的数字串,一步步逼近最佳的答案。

题目描述

设有 n n n 个正整数 a 1 … a n a_1 \dots a_n a1an,将它们联接成一排,相邻数字首尾相接,组成一个最大的整数。

输入格式

第一行有一个整数,表示数字个数 n n n

第二行有 n n n 个整数,表示给出的 n n n 个整数 a i a_i ai

输出格式

一个正整数,表示最大的整数

样例 #1

样例输入 #1

3
13 312 343

样例输出 #1

34331213

样例 #2

样例输入 #2

4
7 13 4 246

样例输出 #2

7424613

提示

对于全部的测试点,保证 1 ≤ n ≤ 20 1 \leq n \leq 20 1n20 1 ≤ a i ≤ 1 0 9 1 \leq a_i \leq 10^9 1ai109

NOIP1998 提高组 第二题


🟢 [NOIP2012 提高组] 国王游戏

此题级别为普及+/提高

与前面一题不同的是,这里增加了变量,考虑时不妨先手动从简单的情形起开始模拟。

题目描述

恰逢 H 国国庆,国王邀请 n n n 位大臣来玩一个有奖游戏。首先,他让每个大臣在左、右手上面分别写下一个整数,国王自己也在左、右手上各写一个整数。然后,让这 n n n 位大臣排成一排,国王站在队伍的最前面。排好队后,所有的大臣都会获得国王奖赏的若干金币,每位大臣获得的金币数分别是:排在该大臣前面的所有人的左手上的数的乘积除以他自己右手上的数,然后向下取整得到的结果。

国王不希望某一个大臣获得特别多的奖赏,所以他想请你帮他重新安排一下队伍的顺序,使得获得奖赏最多的大臣,所获奖赏尽可能的少。注意,国王的位置始终在队伍的最前面。

输入格式

第一行包含一个整数 n n n,表示大臣的人数。

第二行包含两个整数 a a a b b b,之间用一个空格隔开,分别表示国王左手和右手上的整数。

接下来 n n n 行,每行包含两个整数 a a a b b b,之间用一个空格隔开,分别表示每个大臣左手和右手上的整数。

输出格式

一个整数,表示重新排列后的队伍中获奖赏最多的大臣所获得的金币数。

样例 #1

样例输入 #1

3 
1 1 
2 3 
7 4 
4 6

样例输出 #1

2

提示

【输入输出样例说明】

1 1 1 2 2 2 3 3 3 这样排列队伍,获得奖赏最多的大臣所获得金币数为 2 2 2

1 1 1 3 3 3 2 2 2 这样排列队伍,获得奖赏最多的大臣所获得金币数为 2 2 2

2 2 2 1 1 1 3 3 3 这样排列队伍,获得奖赏最多的大臣所获得金币数为 2 2 2

按$ 2$、 3 3 3、$1 $这样排列队伍,获得奖赏最多的大臣所获得金币数为 9 9 9

3 3 3 1 1 1、$2 $这样排列队伍,获得奖赏最多的大臣所获得金币数为 2 2 2

按$ 3$、 2 2 2 1 1 1 这样排列队伍,获得奖赏最多的大臣所获得金币数为 9 9 9

因此,奖赏最多的大臣最少获得 2 2 2 个金币,答案输出 2 2 2

【数据范围】

对于 20 % 20\% 20% 的数据,有 1 ≤ n ≤ 10 , 0 < a , b < 8 1≤ n≤ 10,0 < a,b < 8 1n10,0<a,b<8

对于 40 % 40\% 40% 的数据,有$ 1≤ n≤20,0 < a,b < 8$;

对于 60 % 60\% 60% 的数据,有 1 ≤ n ≤ 100 1≤ n≤100 1n100

对于 60 % 60\% 60% 的数据,保证答案不超过 1 0 9 10^9 109

对于 100 % 100\% 100% 的数据,有 1 ≤ n ≤ 1 , 000 , 0 < a , b < 10000 1 ≤ n ≤1,000,0 < a,b < 10000 1n1,000,0<a,b<10000

NOIP 2012 提高组 第一天 第二题

🟨参考与引用
洛谷
贪心算法基础 (JSOI24 冬令营) 南京大学-蒋炎岩

相关文章:

  • uni-app webview 打开baidu.com
  • 软件设计模式之访问者模式(Visitor Pattern)
  • redis-RedisTemplate.opsForGeo 的geo地理位置及实现附近的人的功能
  • 学会玩游戏,智能究竟从何而来?
  • HarmonyOS开发云工程与开发云函数
  • 加密与安全_探索常用编码算法
  • Vue官网“食用指南”
  • Appium手机Android自动化
  • 数据结构·顺序表实现通讯录
  • 92. 递归实现指数型枚举 刷题笔记
  • LeetCode 热题 100 | 图论(上)
  • spring boot整合cache使用memcached
  • uniapp+node.js前后端做帖子模块:获取帖子列表(社区管理平台的小程序)
  • 本科毕业设计:计及并网依赖性的分布式能源系统优化研究。(C语言实现)(内包含NSGA II优化算法)(一)
  • Mint_21.3 drawing-area和goocanvas的FB笔记(一)
  • docker-consul
  • Fastjson的基本使用方法大全
  • Java教程_软件开发基础
  • ViewService——一种保证客户端与服务端同步的方法
  • 区块链分支循环
  • 移动互联网+智能运营体系搭建=你家有金矿啊!
  • 由插件封装引出的一丢丢思考
  • 运行时添加log4j2的appender
  • 深度学习之轻量级神经网络在TWS蓝牙音频处理器上的部署
  • 【运维趟坑回忆录 开篇】初入初创, 一脸懵
  • 如何用纯 CSS 创作一个菱形 loader 动画
  • ​queue --- 一个同步的队列类​
  • ​油烟净化器电源安全,保障健康餐饮生活
  • (2)STM32单片机上位机
  • (java)关于Thread的挂起和恢复
  • (MIT博士)林达华老师-概率模型与计算机视觉”
  • (二十三)Flask之高频面试点
  • (免费领源码)python#django#mysql公交线路查询系统85021- 计算机毕业设计项目选题推荐
  • (七)Knockout 创建自定义绑定
  • (转载)(官方)UE4--图像编程----着色器开发
  • (转载)深入super,看Python如何解决钻石继承难题
  • *2 echo、printf、mkdir命令的应用
  • .NET BackgroundWorker
  • .net core 6 集成 elasticsearch 并 使用分词器
  • .NET delegate 委托 、 Event 事件
  • .Net 访问电子邮箱-LumiSoft.Net,好用
  • .net 开发怎么实现前后端分离_前后端分离:分离式开发和一体式发布
  • .net 怎么循环得到数组里的值_关于js数组
  • .net 中viewstate的原理和使用
  • .net中应用SQL缓存(实例使用)
  • @FeignClient注解,fallback和fallbackFactory
  • @Import注解详解
  • @param注解什么意思_9000字,通俗易懂的讲解下Java注解
  • [ C++ ] STL_list 使用及其模拟实现
  • [20170713] 无法访问SQL Server
  • [AI]文心一言出圈的同时,NLP处理下的ChatGPT-4.5最新资讯
  • [bbk5179]第66集 第7章 - 数据库的维护 03
  • [BUG] Authentication Error
  • [C#] 如何调用Python脚本程序
  • [c]扫雷