'''
# 贪心算法
贪心算法(贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择,
也就是说,
不从整体最优上加以考虑,他所做的是某种意义上的局部最优解
贪心算法并不保证会得到最优解,但是在某些问题上贪心算法的解就是最优解
要会判断一个问题能否用贪心算法来计算
'''
'''
找零问题,假设商店老板需要找零n元钱,钱币的面额有:
100元 50元 20元 5元 1元
如何找零使得所需钱币的数量最少
从最大钱币开始找
'''
t = [100, 50, 20, 5, 1]
def charge(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(charge(t, 376))
'''
背包问题:
一个小偷在某个商店发现有n个商品,第i个商品价值vi元,重wi千克,他希望拿走的价值尽量高,但他的背包最多只能容乃w千克的东西
他应该拿走哪些商品
0-1背包问题
对于一个商品,小偷要么把它完整拿走,要么留下。不能只拿走一部分,或把一个商品拿走多次(商品为金条)
分数背包问题
对于一个商品,小偷可以拿走其中任意一部分(商品为金砂)
例子:
商品1:v1=60 w1=10
商品2:v2=100 w2=20
商品3:v3=120 w3=30
背包容量:W = 50
'''
goods = [(60, 10), (100, 20), (120, 30)]
goods.sort(key=lambda x: x[0] / x[1], reverse=True)
def fenshu_backpack(goods, W):
m = [0 for _ in range(len(goods))]
total_v = 0
for i, (prize, weight) in enumerate(goods):
if W >= weight:
m[i] = 1
total_v += prize
W -= weight
else:
m[i] = W / weight
total_v += m[i] * prize
W = [0]
break
return m, total_v
print(fenshu_backpack(goods, 50))
'''
拼接最大数字问题:
有n个非负整数,将其按照字符串拼接的方式拼接为一个整数
如何拼接可以使得得到的整数最大
例子;
32,94,128,1286,6,71可以拼接出的最大整数为:
94716321286128
'''
from functools import cmp_to_key
shu = [32, 94, 128, 1286, 6, 71]
def xy_cmp(x, y):
if x + y < y + x:
return 1
elif x + y > y + x:
return -1
else:
return 0
def number_join(shu):
shu = list(map(str, shu))
shu.sort(key=cmp_to_key(xy_cmp))
return "".join(shu)
print(number_join(shu))
'''
活动选择问题
假设有n个活动,这些活动要占用同一片场地,而场地在某时刻只能供一个活动使用
每个活动都有一个开始时间si和结束时间fi,表示活动在[si,fi]区间占用场地
安排哪些活动能够使该场地举办的活动的个数最多?
i 1 2 3 4 5 6 7 8 9 10 11
si 1 3 0 5 3 5 6 8 8 2 12
fi 4 5 6 7 9 9 10 11 12 14 16
'''
'''
贪心结论:最先结束的活动一定是最优解的一部分
证明:
假设a是所有活动中最先结束的活动,b是最优解中最先结束的活动
如果a=b,结论成立
如果a!=b,则b的结束时间一定晚于a的结束时间(剩余的时间可以分给其他活动),
则此时用a换掉最优解中的b,a一定不与最优解中的其他活动时间重叠
因此替换后的解也是最优解
'''
activities = [(1, 4), (3, 5), (0, 6), (5, 7), (3, 9), (5, 9), (6, 10), (8, 11), (8, 12), (2, 14), (12, 16)]
activities.sort(key=lambda x: x[1])
def activity_selection(a):
res = [a[0]]
for i in range(1, len(a)):
if a[i][0] >= res[-1][1]:
res.append(a[i])
return res
print(activity_selection(activities))
'''
动态规划法
基因的比对
序列的相似程度
HMM
'''
'''
斐波那契数列
Fn = F(n-1) +F(n-2)
使用递归和非递归的方式来求解斐波那契数列的第n项
'''
def fibnach(n):
if n == 1 or n == 2:
return 1
else:
return fibnach(n - 1) + fibnach(n - 2)
def fibnach_no_recurision(n):
f = [0, 1, 1]
if n >= 2:
for i in range(n - 2):
num = f[-1] + f[-2]
f.append(num)
return f[n]
print(fibnach_no_recurision(100))
'''
钢条切割问题
某公司出售钢条,出售价格与钢条长度之间的关系如下表:
长度i 1 2 3 4 5 6 7 8 9 10
价格pi 1 5 8 9 10 17 17 20 24 30
问题:
现有一段长度为n的钢条和上面的价格表,求切割钢条方案,使得总收益最大
'''
'''
递推式:
设长度为n的钢条切割后最优收益值为rn,可以得出推导式:
rn = max(pn,r1+rn-1,r2+rn-2,...,rn-1+r1)
第一个参数pn表示不切割
其他n-1个参数分别表示另外n-1种不同切割方案
将钢条切割为长度为i和n-i两端
方案i的收益为切割两端的最优收益之和
遍历所有的i,找到最大的收益的方案
递推式的简化:
rn = max(pi + r(n-i))
只对右边进行切割。左边不再切割
最优子结构:
问题的最优解由相关子问题的最优解组合而成,这些问题可以独立求解
'''
import time
def cal_time(func):
def wrapper(*args, **kwargs):
t1 = time.time()
result = func(*args, **kwargs)
t2 = time.time()
print("%s running time:%s secs." % (func.__name__, t2 - t1))
return result
return wrapper
p = [0, 1, 5, 8, 9, 10, 17, 17, 20, 21, 23, 24, 26, 27, 27, 28, 30, 33, 36, 39, 40]
def cut_rod_recurision_1(p, n):
if n == 0:
return 0
else:
res = p[n]
for i in range(1, n):
res = max(res, cut_rod_recurision_1(p, i) + cut_rod_recurision_1(p, n - i))
return res
def cut_rod_recurision_2(p, n):
if n == 0:
return 0
else:
res = 0
for i in range(1, n + 1):
res = max(res, p[i] + cut_rod_recurision_2(p, n - i))
return res
print(cut_rod_recurision_2(p, 9))
'''
动态规划解法
每个子问题只求解一次,保存求解结果
之后需要此问题时,只需要查找保存的结果
'''
def cut_rod_dp(p, n):
r = [0]
for i in range(1, n + 1):
res = 0
for j in range(1, i + 1):
mid = i - j
res = max(res, p[j] + r[mid])
if p[j] >= p[-1]:
p.append(res)
r.append(res)
return r[n]
print(cut_rod_dp(p, 20))
'''
重构解
对于每个子问题,保存切割一次时左边切下的长度
'''
def cut_rod_extend(p, n):
r = [0]
s = [0]
for i in range(1, n + 1):
res_r = 0
res_s = 0
for j in range(1, i + 1):
mid = i - j
if p[j] + r[mid] > res_r:
res_r = p[j] + r[mid]
res_s = j
r.append(res_r)
s.append(res_s)
return s, r[n]
def cut_rod_solution(p, n):
s, r = cut_rod_extend(p, n)
ans = []
while n > 0:
ans.append(s[n])
n -= s[n]
return ans
s, r = cut_rod_extend(p, 10)
print(s)
print(cut_rod_dp(p, 20))
print(cut_rod_solution(p, 20))