vlambda博客
学习文章列表

笔试刷题 | 贪心算法

定义

贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。


贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即个状态以前的过程不会影响以后的状态,只与当前状态有关。


个人疑惑

这句话能否在现实生活中使用?


因为生活中常常接触的道理是不能短视,要有大局观,牵一发而动全身,不能为了一点蝇头小利而失去自我。


而贪心算法都是基于当前做一个最优选择,以及它的前提是当前状态不影响以后状态,这个前提怎么能做到呢?因为,我们生活中的得失都是之前做出的决断共同造就的呀。


不过,贪心算法并不一定能得到全局最优解,这是肯定的。




#! /usr/bin/env python# -*-coding:utf-8-*-"""Author: ChileWangCreated at 2020/03/20 15:59
Question:贪心算法常用于处理一维度问题,所得的解并不一定是最优解贪心算法的每一次操作都对结果产生直接影响,而动态规划则不是。贪心算法对每个子问题的解决方案都做出选择,不能回退;
动态规划则会根据以前的选择结果对当前进行选择,有回退功能。动态规划主要运用于二维或三维问题,而贪心一般是一维问题 。"""import random

def horse_competition(): n = int(input("输入马匹数目:")) tj = [] # 田忌马匹速度 qw = [] # 齐王马匹速度 reward = 0 for i in range(0, n): tj.append(random.randint(0, 100)) qw.append(random.randint(0, 100)) # 从小到大排序 tj = sorted(tj) qw = sorted(qw) print(tj) print(qw) while len(tj): if tj[0] > qw[0]: # 田忌最慢的马比齐王最慢的马快 reward += 1 del tj[0], qw[0] elif tj[0] == qw[0]: # 田忌最慢马和齐王最慢的马一样 del tj[0], qw[0] else: # 田忌最慢的马比齐王最慢的马垃圾 reward -= 1 del tj[0], qw[-1] # 删除田忌最慢的马和齐王最快的马 print(reward)

def candy_demand(): """ 题目:已知一些孩子和一些糖果,每个孩子有需求因子g, 每个糖果有大小s,当某个糖果的大小s>=某个孩子的需求因子g时, 代表该糖果可以满足该孩子,求使用这些糖果,最多能满足多少孩子 (注意,某个孩子最多只能用1个糖果满足) :return: """ g = [5, 10, 2, 9, 15, 9] s = [6, 1, 20, 3, 8] g = sorted(g) s = sorted(s) print(g) print(s) child = 0 candy = 0 while child < len(g) and candy < len(s): if g[child] <= s[candy]: child += 1 candy += 1 print(child)

def get_max_len(): """ 给定一个整数序列,返回作为摆动序列的最长子序列的长度。 通过从原始序列中删除一些(也可以不删除)元素来获得子序列, 剩下的元素保持其原始顺序。 :return: """ arr = [1, 17, 5, 10, 13, 15, 10, 5, 16, 8] arr = [1,2,3,4,5,6,7,8,9] arr = [1,7,4,9,2,5] if len(arr) < 2: print(len(arr)) else:
# Begin = 0, Up = 1, Down = 2 state = 0 max_len = 1 for i in range(1, len(arr)): if state == 0: if arr[i - 1] < arr[i]: state = 1 max_len += 1 elif arr[i - 1] > arr[i]: state = 2 max_len += 1 elif state == 1: if arr[i - 1] > arr[i]: state = 2 max_len += 1
elif state == 2: if arr[i - 1] < arr[i]: state = 1 max_len += 1 print(max_len)

def remove_digits(): """ 题目:已知一个使用字符串表示非负整数num,将num中的k个数字移除, 求移除k个数字后,可以获得的最小的可能的新数字 (num不会以0开头,num长度小于10002)
例如:输入:num = “1432219”,k=3 在去掉3个数字后得到的很多可能里,如1432,4322,2219,1219;去掉数字4、3、2、得到的1219最小
:return: """ a = "1430219" k = 2 stack = [] for num in a: number = int(num) while stack and k and int(stack[-1]) > number: stack.pop() k -= 1 stack.append(num) while k and stack: stack.pop() k -= 1 print(stack) if not stack: print("0") else: print("".join(stack))

def marry_candy_value(): """ 4.圣诞节发糖果    圣诞节来临了,在城市A中,圣诞老人准备分发糖果。    现在有多箱不同的糖果,每一种糖果都有自己的价值和重量。每箱糖果都可以拆分成任意散装组合带走。圣诞老人的驯鹿最多只能承受一定重量的糖果。请问圣诞老人最多能带走多大价值的糖果。
输入数据:
    输入的第一行由两个部分组成,分别为糖果箱数正整数n(1<=n<=100),驯鹿能承受的最大重量正整数w(0<w<10000);其余n行每行对应一箱糖果,由两部分正整数v和w组成,分别为一箱糖果的价值和重量。
输出要求:
    输出圣诞老人能带走的糖果的最大总价值,保留一位小数,输出为一行。
输出样例:
  4     15
  100  4
  412  8
  266  7
  591  2
输出样例:
  1193.0 :return: """ a = 4 # 箱数 max_load = 15 # 麋鹿最大的载重量 value = [100, 412, 266, 591] # 每种糖果的总价值 load = [4, 8, 7, 2] # 每种糖果的总量 value_per_load = [] # 单位重量价值 list_load_state = [] for i in range(len(value)): avg = round(value[i]/load[i], 1) # 单位重量的价格 value_per_load.append(avg) list_load_state.append([load[i], avg, False]) # [每种糖果对应的总重量, 单位重量的价格, 是否被取走]
value_per_load.sort(reverse=True) # 从大到小排序 all_sum = [0, 0] # 取走的总重量, 取走前的重量备份 sum_value = 0 # 总价值 flag = 0 # 是否超过马车总载重 for i in range(len(value_per_load)): for j in range(len(list_load_state)): if flag == 0: # 重量未超过,标志为0 if value_per_load[i] == list_load_state[j][1] and (not list_load_state[j][2]): all_sum[1] = all_sum[0] # 备份取走前的总量 all_sum[0] += list_load_state[j][0] current_get_load = list_load_state[j][0] if all_sum[0] > max_load: # 大于总载重,循环迭代减少单位重量 flag = 1 # 超出马车最大承重梁, flag=1
while True: z = all_sum[1] + current_get_load # 使用备份重量判断是否超过max_load if z <= max_load: break current_get_load -= 1
all_sum[0] = all_sum[1] # 回复原始的备份载重量 all_sum[0] += current_get_load # 真实拿走的重量 sum_value += value_per_load[i] * current_get_load list_load_state[j][2] = True # 取走标志 else: break print('Value:', sum_value)

def greedy(): """ 一辆汽车加满油后可行驶n公里。旅途中有若干个加油站。 设计一个有效算法,指出应在哪些加油站停靠加油,使沿途加油次数最少。 对于给定的n(n <= 5000)和k(k <= 1000)个加油站位置,编程计算最少加油次数。 :return: """ n = 100 k = 5 d = [50, 80, 39, 60, 40, 32] # 表示加油站之间的距离 num = 0 # 表示加油次数 for i in range(k): if d[i] > n: print('no solution') # 如果距离中得到任何一个数值大于n 则无法计算 return
i, s = 0, 0 # 利用s进行迭代 while i <= k: s += d[i] if s >= n: # 当局部和大于n时, 则局部和更新为当前距离,表示加完油之后已经行驶的距离 s = d[i] # 贪心意在令每一次加满油之后跑尽可能多的距离 num += 1 i += 1 print(num)

if __name__ == '__main__': candy_demand() get_max_len() remove_digits() marry_candy_value() greedy()