贪心算法是算法设计中的一种重要思想,它通过在每一步选择中都采取在当前状态下最好或最优的选择,从而希望导致结果是全局最好或最优的算法。掌握贪心算法对于提高编程能力具有重要意义。本文将带您通过实战习题解析,轻松掌握编程技巧,破解贪心算法难题。
贪心算法概述
贪心算法的定义
贪心算法是一种在每一步选择中都采取当前状态下最好或最优的选择,从而希望导致结果是全局最好或最优的算法。
贪心算法的特点
- 局部最优解:每一步都选择局部最优解,不保证全局最优解。
- 贪心选择:在每一步选择中,总是选择当前状态下最优的选择。
- 无后效性:一旦做出选择,就不会改变这个选择,即不会因为后续情况的变化而改变已做出的选择。
实战习题解析
习题一:最小生成树(Prim算法)
问题描述:给定一个无向连通图,找出图中的最小生成树。
贪心策略:
- 初始化:选取一个顶点作为起点,将其加入最小生成树。
- 遍历图中的所有顶点,选择与最小生成树中顶点距离最近的顶点加入最小生成树。
- 重复步骤2,直到所有顶点都加入最小生成树。
Python代码示例:
class Graph:
def __init__(self, vertices):
self.V = vertices
self.graph = [[0 for column in range(vertices)]
for row in range(vertices)]
def prim_mst(self):
# 初始化最小生成树
min_key = [float('inf')] * self.V
min_key[0] = 0
mst_set = [False] * self.V
parent = [None] * self.V
min_key[0] = 0
parent[0] = -1
for _ in range(self.V):
u = self.min_key_vertex(min_key, mst_set)
mst_set[u] = True
for v in range(self.V):
if self.graph[u][v] and mst_set[v] is False and self.graph[u][v] < min_key[v]:
min_key[v] = self.graph[u][v]
parent[v] = u
return parent
def min_key_vertex(self, key, mst_set):
min = float('inf')
min_index = -1
for v in range(self.V):
if key[v] < min and mst_set[v] is False:
min = key[v]
min_index = v
return min_index
# 创建图
g = Graph(5)
g.graph = [[0, 2, 0, 6, 0],
[2, 0, 3, 8, 5],
[0, 3, 0, 0, 7],
[6, 8, 0, 0, 9],
[0, 5, 7, 9, 0]]
# 执行Prim算法
parent = g.prim_mst()
print("Edge \tWeight")
for i in range(1, len(parent)):
print(f"{parent[i]} - {i} \t{g.graph[i][parent[i]]}")
习题二:背包问题(0-1背包)
问题描述:给定一个背包和一系列物品,每个物品都有重量和价值,求背包能装入的最大价值。
贪心策略:
- 计算每个物品的价值密度(价值/重量)。
- 按价值密度从大到小排序物品。
- 依次将物品放入背包,直到背包容量满或者所有物品都尝试过。
Python代码示例:
def knapsack(W, wt, val, n):
# 初始化价值密度数组
value_density = [0] * n
for i in range(n):
value_density[i] = val[i] / wt[i]
# 按价值密度排序
value_density.sort(reverse=True)
# 初始化背包价值和重量
total_value = 0
total_weight = 0
# 依次将物品放入背包
for i in range(n):
if total_weight + wt[i] <= W:
total_weight += wt[i]
total_value += val[i]
else:
break
return total_value
# 测试背包问题
W = 50
wt = [10, 20, 30]
val = [60, 100, 120]
n = len(val)
print(knapsack(W, wt, val, n))
习题三:最小费用路径
问题描述:给定一个带权重的网格,求从左上角到右下角的最小费用路径。
贪心策略:
- 初始化一个动态规划数组,用于存储到达每个节点的最小费用。
- 从左上角开始,依次计算到达每个节点的最小费用。
- 返回到达右下角的最小费用。
Python代码示例:
def min_cost_path(cost, m, n):
# 初始化动态规划数组
dp = [[0] * n for _ in range(m)]
# 初始化起点费用
dp[0][0] = cost[0][0]
# 计算第一行和第一列的最小费用
for i in range(1, m):
dp[i][0] = dp[i - 1][0] + cost[i][0]
for j in range(1, n):
dp[0][j] = dp[0][j - 1] + cost[0][j]
# 计算其他节点的最小费用
for i in range(1, m):
for j in range(1, n):
dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + cost[i][j]
return dp[m - 1][n - 1]
# 测试最小费用路径
cost = [[1, 3, 1],
[4, 2, 1],
[1, 5, 3]]
m, n = len(cost), len(cost[0])
print(min_cost_path(cost, m, n))
总结
通过以上实战习题解析,我们可以看到贪心算法在解决实际问题时具有很高的应用价值。掌握贪心算法,可以帮助我们更好地解决编程问题,提高编程技巧。在实际应用中,我们需要根据具体问题选择合适的贪心策略,以达到最优解。希望本文对您有所帮助。
