标签:背包问题 就是 .com sed 组合 max 相关 字符串拼接 pac
贪心算法是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。
贪心算法并不保证会得到最优解,但是在某些问题上贪心算法的解就是最优解。要会判断一个问题能否用贪心算法来计算。
假设商店老板需要找零n元钱,钱币的面额有:100元,50元,20元,5元,1元,如何找零是的所需钱币的数量最少?
t = [100, 50, 20, 5, 1] def change(t, n): m = [0 for i 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个商品价值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 fractional_backpack(goods, w): m = [0 for i in range(len(goods))] total_v = 0 for i, (price, weight) in enumerate(goods): if w >= weight: m[i] = 1 total_v += price w -= weight else: m[i] = w / weight total_v += m[i] * price w = 0 break return total_v, m print(fractional_backpack(goods, 50))
有n个非负整数,将其按照字符串拼接的方式拼接为一个整数。如何拼接可以使得得到的整数最大?
例例:32,94,128,1286,6,71可以拼接除的最?大整数为
94716321286128
li = [32, 94, 128, 1286, 6, 71] def number_join(li): li = list(map(str, li)) for i in range(len(li) - 1): for j in range(len(li) - i - 1): if li[j] + li[j + 1] < li[j + 1] + li[j]: li[j], li[j + 1] = li[j + 1], li[j] return "".join(li) print(number_join(li))
假设有n个活动,这些活动要占?用同?一?片场地,?而场地在某时刻只能供?一个活动使?用。
每个活动都有?一个开始时间si和结束时间fi(题?目中时间以整数表示),表示活动在[si, fi)区间占?用场地。
贪心讨论:最先结束的活动一定是最优解的一部分。
证明:假设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))
斐波那契数列列:Fn = Fn−1 + Fn−2
练习:使?用递归和?非递归的?方法来求解斐波那契数列列的第n项
# 子问题的重复计算 def fibnacci(n): if n > 0: if n == 1 or n == 2: return 1 else: return fibnacci(n-1) + fibnacci(n-2) # 动态规划(DP)的思想 = 递归式 + 重复子问题 def fibnacci_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]
某公司出售钢条,出售价格与钢条?长度之间的关系如下表:
问题:现有?一段?长度为n的钢条和上?面的价格表,求切割钢条?方案,使得总收益最?大。
设?长度为n的钢条切割后最优收益值为rn,可以得出递推式:rn = max(pn,r1+rn-1,r2+rn-2,…,rn-1+r1),
第?个参数pn表示不不切割
其他n-1个参数分别表示另外n-1种不不同切割?方案,对方案i=1,2,...,n-1
将钢条切割为长度为i和n-i两段
方案i的收益为切割两段的最优收益之和
考察所有的i,选择其中收益最大的?案
可以将求解规模为n的原问题,划分为规模更更小的子问题:完成?一次切割后,可以将产?生的两段钢条看成两个独?立的钢条切个问题。
组合两个子问题的最优解,并在所有可能的两段切割方案中选取组合收益最大的,构成原问题的最优解。
钢条切割满足最优子结构:问题的最优解由相关?问题的最优解组合而成,这些子问题可以独立求解。
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
## 实现复杂度O(2n) 2的n次方, 效率指数型增长,效率非常慢
递归算法由于重复求解相同子问题,效率极低
动态规划的思想:
1. 每个子问题之求解一次,保存求解结果
2. 之后需要此问题时,只需要查找保存的结果
def cut_rod_dp(p, n): r = [0] for i in range(1, n+1): res = 0 for j in range(1, i+1): res = max(res, p[j] + r[i - j]) r.append(res) return r[n]
## 时间复杂度为O(n的平方)
如何修改动态规划算法,使其不不仅输出最优解,还输出最优切割?方案?
对于每个子问题,保存切割一次时左边切下的长度
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): if p[j] + r[i - j] > res_r: res_r = p[j] + r[i - j] res_s = j r.append(res_r) s.append(res_s) return r[n], s
一个序列的子序列是在该序列中删去若干元素后得 到的序列。
例:“ABCD”和“BDF”都是“ABCDEFG”的?序列
最长公共?子序列(LCS)问题:给定两个序列X和Y,求X和Y?度最?的公共?序列。
例:X="ABBCBDE" Y="DBBCDB" LCS(X,Y)="BBCD"
应?场景:字符串相似度?对
例如:要求a="ABCBDAB"与b="BDCABA"的LCS:
由于最后?位"B"≠"A":
因此LCS(a,b)应该来源于LCS(a[:-1],b)与LCS(a,b[:-1])中更大的那?个
def lcs_length(x, y): m = len(x) n = len(y) c = [[0 for _ in range(n+1)] for _ in range(m+1)] for i in range(1, m+1): for j in range(1, n+1): if x[i-1] == y[j-1]: # i j 位置上的字符匹配的时候,来自于左上方+1 c[i][j] = c[i-1][j-1] + 1 else: c[i][j] = max(c[i-1][j], c[i][j-1]) return c[m][n] def lcs(x, y): m = len(x) n = len(y) c = [[0 for _ in range(n + 1)] for _ in range(m + 1)] b = [[0 for _ in range(n + 1)] for _ in range(m + 1)] # 1 左上方 2 上方 3 左方 for i in range(1, m+1): for j in range(1, n+1): if x[i-1] == y[j-1]: # i j 位置上的字符匹配的时候,来自于左上方+1 c[i][j] = c[i-1][j-1] + 1 b[i][j] = 1 elif c[i-1][j] > c[i][j-1]: # 来自于上方 c[i][j] = c[i-1][j] b[i][j] = 2 else: c[i][j] = c[i][j-1] b[i][j] = 3 return c[m][n], b def lcs_trackback(x, y): c, b = lcs(x, y) i = len(x) j = len(y) res = [] while i > 0 and j > 0: if b[i][j] == 1: # 来自左上方=>匹配 res.append(x[i-1]) i -= 1 j -= 1 elif b[i][j] == 2: # 来自于上方=>不匹配 i -= 1 else: # ==3 来自于左方=>不匹配 j -= 1 return "".join(reversed(res)) print(lcs_trackback("ABCBDAB", "BDCABA"))
标签:背包问题 就是 .com sed 组合 max 相关 字符串拼接 pac
原文地址:https://www.cnblogs.com/Xuuuuuu/p/10853152.html