一文弄懂贪心算法(python)

贪心概念:

把整体问题分解成多个步骤,在每个步骤都选取当前步骤的最优方案,直至所有步骤结束;每个步骤不会影响后续步骤。

核心性质:

每次采用局部最优,最终结果就全局最优。
如果题目满足上述核心性质,则可以采用贪心进行求解。

硬币支付问题

最少硬币支付问题:假设有三种硬币:1元、2元、5元,数量不限,现在需要支付M元,要求硬币数目最少,应该如何支付?
局部最优:要保证硬币尽可能少,所以当前尽可能选择大面值的硬币
此问题只要采用局部最优就能得到全局最优

5元 比1元和2元都大,所以选面额更大的5元比选前面的硬币加起来都大。

如果把硬币面值改成1元、2元、4元、5元、6元,现在支付9元,按照贪心:6+2+1,需要3个硬币,但是最优结果:4+5,并不是所有采用局部最优都能得到全局最优。

但是此处4+5是大于6的所以最优并不一定是选6。


如何判断是否能用贪心?

1、最优子结构性质:当一个问题的最优解包含子问题的最优解,则称之为具有最优子结构性质。
2、贪心性质选择:可以通过局部最优的选择得到全局最优

具体问题如何做?

1、经验性积累各种类型的贪心
2、举反例

经典贪心

1.石子合并问题

每次选择最小的两个,利用堆。

蓝桥545

一文弄懂贪心算法(python)_第1张图片

import os
import sys

# 请在此输入您的代码
import heapq #堆
ans = 0
n = int(input()) 
a = list(map(int,input().split()))
heapq.heapify(a) #把a转为堆
while len(a) >= 2:
  x = heapq.heappop(a) #推出最小的
  y = heapq.heappop(a) #推出目前第二小的
  heapq.heappush(a,x+y) #合并两个部落
  ans += x + y 更新答案
print(ans)

2.分箱问题:

尽可能多放,不浪费空间。

蓝桥532

一文弄懂贪心算法(python)_第2张图片

import os
import sys

# 请在此输入您的代码
w = int(input())
n = int(input())
b = []
ans = 0
for i in range(n):
  b.append(int(input()))
b.sort() #排序
l, r = 0, len(b) - 1 #双指针,左端点和右端点
while True: #死循环,直至break才退出
  if l == r: #如果左端点等于右端点,说明未分组的只剩一个了,只能分一组,答案+1
    ans += 1
    break
  if l > r: #如果左端点大于右端点,全部分组好了
    break
  if b[l] + b[r] > w: #如果上面两种情况都没有出现,那就判断是否能分组,如果不符合分组条件,答案+1
    ans += 1  #右端点-1是因为大的自己分一组
    r -= 1
  else:
    ans += 1
    r -= 1 #大的小的分成一组,然后左端点,右端点都更新。
    l += 1
print(ans)

3.翻硬币问题

蓝桥209

一文弄懂贪心算法(python)_第3张图片

最简单的思想:
这种策略对吗?从左往右翻
从左往右第一个不同的位置,一定需要翻,才能保证该位置满足,一个位置最多翻一次。
 

import os
import sys

# 请在此输入您的代码
a = list(input())
b = list(input())
n =len(a)
ans = 0
for i in range(n):
  if a[i] == b[i]: #如果相同则不翻,继续看下一个相同不
    continue
  else:            #如果不同,一定要翻,实际上是找第一个不同的硬币
    if b[i+1] == '*': 
      b[i+1] = 'o'
    else:
      b[i+1] = '*'
  ans += 1 #更新答案
print(ans)
#字符串不能直接改变,记得看数据类型(一般都是转换为列表)

数组累积问题:

一文弄懂贪心算法(python)_第4张图片

总结步骤:

  1. 判断是否能用贪心
  2. 找到真正子问题,寻找局部最优解
  3. 推导全局最优解,自己要穷举大部分情况,看看是否有反例与假设违背

你可能感兴趣的:(蓝桥杯备赛,贪心算法,算法,python)