贪心算法——经典案例分析

目录

案例一:找零钱 

案例二:活动安排

案例三:单源最短路径


贪心算法(Greedy Algorithm)是一种基于贪心策略的算法设计方法,它在每一步选择中都采取当前状态下最优的选择,以期望达到全局最优解。贪心算法通常适用于那些具有最优子结构性质的问题,即问题的最优解可以通过子问题的最优解来构造。

贪心算法的基本思想可以简单概括为:

  1. 选择策略:在每一步,从所有可选的选择中选择当前看起来最优的那个。

  2. 局部最优:通过选择局部最优解来构建全局最优解。

  3. 无后效性:每一步的选择只依赖于当前状态,不受之后的影响。

尽管贪心算法在许多情况下能够得到高效的解决方案,但它并不适用于所有问题。因为它没有考虑全局的状态,有时可能会导致得到次优解或者根本无法得到解。


案例一:找零钱 

问题:假设你是一个收银员,你需要找给顾客一定数量的零钱。你手上有一些面额不同的硬币(比如1元、5元、10元、20元、50元)。目标是找给顾客最少数量的硬币。

方法

  1. 优先使用大面额的硬币。

  2. 如果顾客需要的金额超过当前最大面额的硬币,就使用一个最大面额的硬币,然后继续往下找零。

  3. 重复上述步骤,直到找完所有需要的零钱。

def give_change(amount, coins):
    coins.sort(reverse=True)  # 按面额从大到小排序
    change = []  # 用来存放找零的硬币列表

    for coin in coins:
        while amount >= coin:
            change.append(coin)
            amount -= coin

    return change

# 测试
amount = 30
coins = [1, 5, 10, 20, 50]
change = give_change(amount, coins)
print("找零的硬币列表:", change)

案例二:活动安排

问题:假设你是一个活动策划师,现在你手上有一系列活动,每个活动都有一个开始时间和结束时间。你希望安排尽可能多的活动,但是由于时间的限制,你不能同时安排两个活动。你的目标是找出安排的最大数量的活动。

方法

  1. 首先,将所有活动按照结束时间从早到晚排序。

  2. 选择第一个结束时间最早的活动,并将其安排上日程。

  3. 依次考虑后续活动,如果活动的开始时间晚于或等于上一个活动的结束时间,则可以安排该活动。

  4. 重复上述步骤,直到所有活动都考虑完毕。 

def activity_selection(start_times, end_times):
    # 将开始时间和结束时间打包成一个元组列表
    activities = list(zip(start_times, end_times))  
    # 按结束时间从早到晚排序
    activities.sort(key=lambda x: x[1])  
    selected_activities = []

    end_time = 0
    for activity in activities:
        start, end = activity
        if start >= end_time:
            selected_activities.append(activity)
            end_time = end

    return selected_activities

# 测试
start_times = [1, 3, 0, 5, 3, 5, 6, 8]
end_times = [4, 5, 6, 7, 8, 9, 10, 11]
selected = activity_selection(start_times, end_times)

# 输出选中的活动
print("选中的活动:", selected)

案例三:单源最短路径

问题:给定一个带权重的有向图和一个起始节点,我们想要找到从起始节点到图中所有其他节点的最短路径。

方法Dijkstra算法,其基本思想贪心算法。

  1. 初始化:为每个节点设置一个距离值,初始时将起始节点的距离设为0,其他节点的距离设为无穷大。将所有节点放入一个优先队列(最小堆)中,按照距离值进行排序。

  2. 选择最近节点:从优先队列中取出距离起始节点最近的节点。

  3. 更新相邻节点的距离:对于被选中的节点,遍历其所有相邻节点,更新它们的距离值。如果通过当前节点到达相邻节点的路径比之前计算的路径更短,就更新相邻节点的距离值。

  4. 重复步骤2和3:重复选择最近节点和更新相邻节点的距离,直到所有节点都被处理过或者优先队列为空。

  5. 最终结果:当所有节点都被处理完毕后,得到了从起始节点到所有其他节点的最短路径。

import heapq

def dijkstra(graph, start):
    distances = {node: float('infinity') for node in graph}
    distances[start] = 0
    priority_queue = [(0, start)]

    while priority_queue:
        current_distance, current_node = heapq.heappop(priority_queue)

        if current_distance > distances[current_node]:
            continue

        for neighbor, weight in graph[current_node].items():
            distance = current_distance + weight
            if distance < distances[neighbor]:
                distances[neighbor] = distance
                heapq.heappush(priority_queue, (distance, neighbor))

    return distances

# 示例图的邻接表表示
graph = {
    'A': {'B': 10, 'C': 5},
    'B': {'D': 5},
    'C': {'B': 1, 'D': 2},
    'D': {'A': 3}
}

# 使用Dijkstra算法找到从A到所有其他节点的最短路径
shortest_paths = dijkstra(graph, 'A')

# 输出最短路径
for node, distance in shortest_paths.items():
    print(f'Shortest path from A to {node} is {distance}')

你可能感兴趣的:(算法学习,贪心算法,算法,学习)