首页 > 编程语言 >备战蓝桥杯Day28 - 贪心算法

备战蓝桥杯Day28 - 贪心算法

时间:2024-03-21 23:32:04浏览次数:28  
标签:函数 Day28 蓝桥 算法 enumerate 最优 贪心 lambda

一、贪心算法

贪心算法(Greedy Algorithm)是一种在每一步选择中都采取在当前状态下最好或最优(即最有利)的选择,从而希望导致结果是全局最好或最优的算法。贪心算法在有最优子结构的问题中尤为有效。最优子结构指的是问题的最优解可以由子问题的最优解有效地构造出来。贪心算法与动态规划不同,它自顶向下做出贪心选择,不做回溯。

贪心算法的基本思路是:

  1. 建立数学模型来描述问题。
  2. 把求解的问题分成若干个子问题。
  3. 对每一子问题求解,得到子问题的局部最优解。
  4. 把子问题的局部最优解合成原来问题的一个解。

希望利用贪心算法得到问题的整体最优解,必须注意两条性质:

  • 贪心选择性质:这是指所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。贪心选择是采用从顶向下、以迭代的方式做出相继选择,每做一次选择就将所求问题简化为一个规模更小的子问题。
  • 最优子结构性质:当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质。问题的最优子结构性质是该问题可用贪心算法或动态规划算法求解的关键特征。

贪心算法的优缺点如下:

  • 优点:算法简单,效率高,省去了为找最优解要穷尽所有可能而必须耗费的大量时间。贪心算法不是对所有问题都能得到整体最优解,但对范围相当广泛的许多问题它能产生整体最优解或者是整体最优解的近似解。
  • 缺点:因为它并不从整体最优上加以考虑,它在某些情况下所求得的解可能不是整体最优解,只是某种意义上的局部最优解。

二、找零问题 

?假设商店老板需要找零n元钱,钱币的面值有:100元、50元、20元、5元、1元,如何找零使得所需钱币的数量最少。

=>思路:

1、利用贪心算法,每次找最优解,先找面值最大的张数,因为面值最大,所需要的张数就会小

2、通过对要找零的钱数取余,再去寻找下一个面值最大的张数,这样循环实现。

代码实现:

t = [100, 50, 20, 5, 1]


def change(t, n):
    m = [0 for _ in range(len(t))]  # 通过列表推导式定义面值所对应的张数
    for i, money in enumerate(t):
        m[i] = n // money
        n = n % money
    return m, n


print(change(t, 376))

三、背包问题 - 分数背包

?问题描述

一个小偷在某个商店发现有n个商品,第i个商品价值v元,重w千克。他希望拿走的价值尽量高,但他的背包最多只能容纳W千克的东西。他应该拿走哪些商品?

商品1: V1=60  W1=10

商品2: V2=100 W2=20 

商品3: V3=120 W3=30

背包容量:W=50

分数背包: 对于一个商品,小偷可以拿走其中任意一部分。(商品为金砂)

问题思路

通过比较每一个商品的单价来确定要优先拿哪一个商品,拿到商品后将商品数量置为1,将背包的重量减少,计算商品价值综合,此通过循环比较来实现。

在开始算法之前先对商品的单价进行排序,用到了lambda匿名函数,对物品的价格,重量循环便利的时候用到了enumerate函数。

代码实现:

goods = [(60, 10), (120, 30), (100, 20)]
# 先将商品的单价从大到小排序
goods.sort(key=lambda x: x[0]/x[1], reverse=True)


def fractional_backpack(goods, w):
    m = [0 for _ in range(len(goods))]   # 创建列表记录带走商品的数量
    total_val = 0
    for i, (price, weight) in enumerate(goods):
        if w > weight:   # 背包有足够空余的空间带走商品
            m[i] = 1
            total_val += price  # 更新价格和重量
            w -= weight
        else:
            m[i] = w/weight
            total_val += price * m[i]   #计算带走几分之几的价格
            w = 0
            break
    return  total_val, m


print(fractional_backpack(goods, 50))

ps:

lambda函数

lambda 函数是 Python 中的一个轻量级的匿名函数,它允许你快速定义一个只有一行表达式的简单函数。lambda 函数没有自己的名称,因此也被称为匿名函数。它主要用于需要一个函数作为参数的场合,而无需显式地定义一个单独的函数。

lambda 函数的基本语法如下:

lambda arguments: expression
  • arguments 是 lambda 函数的参数,可以有一个或多个,用逗号分隔。
  • expression 是 lambda 函数的返回值,只能有一个表达式。

示例:

# 定义一个简单的 lambda 函数,它接受两个参数并返回它们的和  
add = lambda x, y: x + y  
  
# 使用 lambda 函数  
result = add(3, 4)  
print(result)  # 输出: 7

 

在这个例子中,add 是一个 lambda 函数,它接受两个参数 x 和 y,并返回它们的和。然后我们调用这个 lambda 函数,传入 3 和 4,得到结果 7。

lambda 函数经常与 Python 的内置函数如 map()filter()reduce() 等一起使用,这些函数接受一个函数作为参数,并对序列进行某种操作。

例如,使用 map() 函数和 lambda 函数来将列表中的每个元素平方:

numbers = [1, 2, 3, 4, 5]  
squared = map(lambda x: x ** 2, numbers)  
print(list(squared))  # 输出: [1, 4, 9, 16, 25]

 

在这个例子中,lambda x: x ** 2 是一个简单的 lambda 函数,它接受一个参数 x 并返回 x 的平方。我们使用 map() 函数将这个 lambda 函数应用到 numbers 列表的每一个元素上,得到一个新的迭代器 squared,然后将其转换为列表输出。

虽然 lambda 函数很有用,但它并不适合定义复杂的函数逻辑。对于更复杂的函数,应该使用 def 关键字来定义具名的函数。

 enumerate函数

enumerate() 是 Python 的内置函数,用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中。

enumerate() 函数的语法如下:

enumerate(iterable, start=0)

参数说明:

  • iterable:一个可遍历的对象,如列表、元组或字符串。
  • start(可选):计数起始值,默认为0。

enumerate() 函数返回的是一个枚举对象,它生成由数据对象的元素和其下标(默认从0开始)组成的元组。

下面是一个使用 enumerate() 函数的简单示例

# 创建一个列表  
fruits = ['apple', 'banana', 'cherry']  
  
# 使用 enumerate() 函数遍历列表  
for index, fruit in enumerate(fruits):  
    print(f"Index {index}: {fruit}")

输出将会是:

Index 0: apple  
Index 1: banana  
Index 2: cherry

在这个例子中,enumerate(fruits) 为列表中的每个元素生成了一个元组,其中包含元素的索引和值。然后,for 循环将这两个值分别赋值给 index 和 fruit 变量,并打印出来。

如果你想要从1开始计数,而不是默认的0,你可以将 start 参数设置为1:

# 创建一个列表  
fruits = ['apple', 'banana', 'cherry']  
  
# 使用 enumerate() 函数遍历列表,从1开始计数  
for index, fruit in enumerate(fruits, start=1):  
    print(f"Index {index}: {fruit}")

输出将会是:

Index 1: apple  
Index 2: banana  
Index 3: cherry

这样,enumerate() 函数就可以很方便地在遍历序列的同时获取到元素的索引。

学习碎碎念

总是急着想要一下就成为很厉害的人,但是没有脚踏实地的努力和日复一日的学习都是空想!一步一步的来吧,不一定慢慢来,但要沉下心一步一步的来 。

“请深耕细作自己,长成一帜独树,欣欣浇灌,独当天地。”

标签:函数,Day28,蓝桥,算法,enumerate,最优,贪心,lambda
From: https://blog.csdn.net/2301_78820199/article/details/136749731

相关文章

  • 中位数贪心
    中位数贪心题目1题目链接462.最小操作次数使数组元素相等II-力扣(LeetCode)题目大意给你一个长度为n的整数数组nums,返回使所有数组元素相等需要的最小操作数。在一次操作中,你可以使数组中的一个元素加1或者减1。示例输入:nums=[1,2,3]输出:2解释:只需要两次操......
  • 第十四届蓝桥杯大赛软件赛省赛Python 《三国游戏》
    问题描述问题类型排序,贪心算法。问题分析当第i个事件发生时会分别让X,Y,Z增加Ai,Bi,Ci即当某个事件发生时,三国各增加士兵数Ai,Bi,Ci。如果X,Y,Z的其中一个大于另外两个之和,我们认为其获胜。即当n个事件都确定了是否会发生后,存在X,Y,Z中任一大于另外两个之和,则有其中一个国家获......
  • 24/03/19 贪心(一)
    (1)CF1684DTraps有\(n\)个数字\(a_1\sima_n\)排成一排,你需要从左到右依次越过所有数。两种越过\(i\)的方式:花费\(a_i\)的代价越过;花费\(0\)的代价越过,后面的\(a_i\)都加\(1\)。现在你拥有最多\(k\)次操作二的机会,求最小的代价总和。一定会使用\(k\)......
  • 蓝桥杯-翻转
    """题目来源:https://www.lanqiao.cn/problems/3520/learning/?page=1&first_category_id=1&name=%E7%BF%BB%E8%BD%AC"""importosimportsysimportcopy#请在此输入您的代码n=int(input())#n组测评数据data=[[]foriinrange(n)]for......
  • 蓝桥杯-百亿富翁
    """https://www.lanqiao.cn/problems/1142/learning/"""importosimportsys#请在此输入您的代码n=int(input())a=list(map(int,input().split()))#求右边第一个比其高的楼房编号defright(a,n):#单调栈stack=[]#ans[i]记录右边第一座比......
  • 第十三届蓝桥杯省赛A组
    目录试题A:裁纸刀试题C:质因数个数埃拉托斯特尼筛法求素数试题J:数的拆分题解试题A:裁纸刀分析:可以举几个例子出来发现规律是:4+(m-1)+(n-1)m;4表示边缘4刀,m-1表示横着切的数量,(n-1)m表示竖着切的数量结果:4+19+21*20=443试题C:质因数个数埃拉托斯特尼筛法求素数分析:先列......
  • 蓝桥杯——盾神与格子游戏(动态规划+递推)
    资源限制内存限制:256.0MB C/C++时间限制:1.0s Java时间限制:3.0s Python时间限制:5.0s问题描述在盾神很小很小还不会怎样编程的时候,他迷上了一款风靡一时的双人游戏!游戏双方在地上画n个格子,然后在最后一格放上一颗石头。每人每轮可以把石头向前移动1到3格,最后谁把......
  • 管道(蓝桥杯)
    有一根长度为\(len\)的横向的管道,该管道按照单位长度分为\(len\)段,每一段的中央有一个可开关的阀门和一个检测水流的传感器。一开始管道是空的,位于\(L_i\)的阀门会在\(S_i\)时刻打开,并不断让水流入管道。对于位于\(L_i\)的阀门,它流入的水在\(T_i\)(\(T_i\geS_i\))时......
  • 贪心算法详解
    贪心1建立数学模型来描述问题2把求解的问题分成若干个子问题3对每一个子问题求解,得到子问题的局部最优解4把子问题的解局部最优解合成原来解问题的一个解总结:局部最优做到全局最优。例题实战1在很久以前,有n个部落居住在平原上,依次编号为1到n,第i个部落的人数为ti,......
  • 【leetcode】135_candy糖果题_贪心算法_C语言_唐完了之后是?(雾
    原题如下:(蓝字为原题链接,可跳转查看)135.分发糖果n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分。你需要按照以下要求,给这些孩子分发糖果:每个孩子至少分配到 1 个糖果。相邻两个孩子评分更高的孩子会获得更多的糖果。请你给每个孩子分发糖果,计算并......