📅  最后修改于: 2023-12-03 15:28:13.203000             🧑  作者: Mango
贪婪方法(Greedy Algorithm)是指在每一步选择中都采取在当前状态下最好或最优(即最有利)的选择,从而希望导致结果是全局最好或最优的算法。
贪婪方法的优点是简单、高效、容易实现,常常可以作为一种近似求解问题的方法。但是,由于贪婪方法每一步都只考虑当前状态,而不考虑长远的影响,因此并不能保证求得的是最优解。
动态规划(Dynamic Programming)是一种通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。它的基本思想是:将待求解问题分解为若干个子问题,先求解子问题,然后根据子问题的解推导出原问题的解。
由于动态规划可以避免重复计算,对于有很多重叠子问题和子问题数目巨大的问题,动态规划算法具有优异的效率。
贪心算法与动态规划都是一种基于分治思想的算法。但是,它们之间也存在一些差别。
贪心算法采取每次选择当前状态下最优的策略,从而希望获得全局最优解,因此贪心算法是一种自顶向下的思想。但是贪心算法不能保证得到全局最优解,它只能得到一个近似最优解。
动态规划是一种自底向上的思想。它会将问题分解为若干个子问题,先求解子问题,然后根据子问题的解推导出原问题的解。动态规划算法可以通过记忆化搜索避免重复计算,因此在解决决策问题时非常有效。
贪心算法和动态规划常常用于解决最优化(优化的解也可以通过比较来得到)问题。其中,贪心算法主要用于解决局部最优问题,比如最小生成树问题、哈夫曼编码问题、背包问题等;动态规划主要用于解决多阶段决策问题,比如最长公共子序列问题、0-1背包问题等。
以背包问题为例,可以采用贪心算法求解。假设有一个背包可以容纳$W$重量的物品,现在有$n$个物品,每个物品的重量为$w[i]$,价值为$v[i]$,问如何选择物品,使得背包装下的物品总价值最大?
class Thing:
def __init__(self, w, v):
self.w = w
self.v = v
self.ratio = v / w # 计算性价比
def knapsack(n, capacity, things):
things.sort(key=lambda x: x.ratio, reverse=True) # 将物品按性价比从大到小排序
total_value = 0
total_weight = 0
i = 0
while total_weight < capacity and i < n:
if things[i].w <= capacity - total_weight: # 如果当前物品可以全部装进背包
total_weight += things[i].w
total_value += things[i].v
else: # 否则只能装一部分
total_value += things[i].ratio * (capacity - total_weight)
total_weight = capacity
i += 1
return total_value
以0-1背包问题为例,假设有一个背包可以容纳$W$重量的物品,现在有$n$个物品,每个物品的重量为$w[i]$,价值为$v[i]$,问如何选择物品,使得背包装下的物品总价值最大?
def knapsack(n, capacity, weight, value):
dp = [[0 for j in range(capacity + 1)] for i in range(n + 1)]
for i in range(1, n + 1):
for j in range(1, capacity + 1):
if weight[i - 1] <= j:
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i - 1]] + value[i - 1])
else:
dp[i][j] = dp[i - 1][j]
return dp[n][capacity]
贪婪方法与动态规划是求解最优化问题的两种基本算法,在实际应用中,需要根据具体问题的特点选择合适的算法。贪心算法不需要消耗大量的时间和空间,因此在对求解速度要求比较高的场景中比较适用;而动态规划算法求解出来的一定是最优解,但需要占用大量的空间和时间,因此在对精度、效率都有较高要求的场景中比较适用。