贪心算法(Greedy Algorithm)是一类在每一步选择中都做出当前最优解,以期望通过一系列局部最优选择达到全局最优解的算法。贪心算法的核心思想是通过一次次的局部优化来构建全局解。尽管这种方法不总是能找到全局最优解,但在许多情况下,贪心算法能提供一个有效且接近最优的解。
贪心算法的基本特征
1. **贪心选择性质**:每一步都做出一个看似最优的选择,即局部最优选择。这种选择不考虑未来的结果,只是当前的最佳选项。
2. **最优子结构性质**:问题的全局最优解包含了其子问题的最优解。换句话说,贪心算法的选择步骤可以用于解决子问题,并且这些子问题的解可以组合成全局最优解。
贪心算法的应用场景
贪心算法在解决某些特定类型的问题时非常有效,常见的应用场景包括但不限于:
1. **最短路径问题**:如Dijkstra算法用于单源最短路径。
 2. **最小生成树问题**:如Kruskal和Prim算法。
 3. **活动选择问题**:如安排最大数量的不重叠活动。
 4. **背包问题**:如分数背包问题(Fractional Knapsack Problem)。
 5. **霍夫曼编码**:用于数据压缩的霍夫曼树构建。
贪心算法的设计步骤
1. **选择贪心策略**:确定每一步的贪心选择标准。
 2. **证明贪心选择的正确性**:确保每一步选择不会影响最终的全局最优解。
 3. **证明最优子结构**:确保每个子问题的最优解可以组合成全局问题的最优解。
 4. **构建算法**:将贪心选择策略应用于具体问题,构建完整的算法步骤。
贪心算法的优缺点
优点
- **简单高效**:贪心算法通常比动态规划和回溯算法更为简单,并且能够更快速地找到解。
 - **实时性强**:在某些情况下,贪心算法能迅速给出一个可行解,这在需要实时决策的问题中尤为重要。
缺点
- **不保证最优解**:贪心算法不总是能找到全局最优解,尤其是当局部最优解无法组合成全局最优解时。
 - **需要问题特性支持**:贪心算法只有在满足贪心选择性质和最优子结构性质的问题上才能有效应用。
经典案例分析
 1. 分数背包问题
 在分数背包问题中,我们有一个容量为W的背包和n种物品,每种物品都有一个重量和价值。目标是选择物品装入背包,使得总价值最大化,并且可以分割物品。
**贪心策略**:选择单位重量价值最高的物品,尽可能装入背包。
```python
 class Item:
     def __init__(self, value, weight):
         self.value = value
         self.weight = weight
def fractional_knapsack(items, capacity):
     # 按照单位重量价值排序
     items.sort(key=lambda x: x.value / x.weight, reverse=True)
     
     total_value = 0.0
     for item in items:
         if capacity >= item.weight:
             total_value += item.value
             capacity -= item.weight
         else:
             total_value += item.value * (capacity / item.weight)
             break
     
     return total_value
items = [Item(60, 10), Item(100, 20), Item(120, 30)]
 capacity = 50
 print(f'最大价值: {fractional_knapsack(items, capacity)}')
 ```
#### 2. 活动选择问题
 在活动选择问题中,我们有一组活动,每个活动都有一个开始时间和结束时间。目标是选择最大的非重叠活动集。
**贪心策略**:每次选择结束时间最早且不与已选择活动重叠的活动。
```python
 def activity_selection(activities):
     # 按结束时间排序
     activities.sort(key=lambda x: x[1])
     
     selected_activities = []
     last_end_time = 0
     
     for activity in activities:
         if activity[0] >= last_end_time:
             selected_activities.append(activity)
             last_end_time = activity[1]
     
     return selected_activities
activities = [(1, 4), (3, 5), (0, 6), (5, 7), (3, 8), (5, 9), (6, 10), (8, 11)]
 print(f'选择的活动: {activity_selection(activities)}')
 ```