笔试刷题 | 贪心算法
定义
贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。
贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。
个人疑惑
这句话能否在现实生活中使用?
因为生活中常常接触的道理是不能短视,要有大局观,牵一发而动全身,不能为了一点蝇头小利而失去自我。
而贪心算法都是基于当前做一个最优选择,以及它的前提是当前状态不影响以后状态,这个前提怎么能做到呢?因为,我们生活中的得失都是之前做出的决断共同造就的呀。
不过,贪心算法并不一定能得到全局最优解,这是肯定的。
#! /usr/bin/env python
# -*-coding:utf-8-*-
"""
Author: ChileWang
Created 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()