C++中的贪心算法
贪心算法概述
贪心算法(Greedy Algorithm)是一种在每一步选择中都采取当前状态下最优(局部最优)的决策,从而希望导致全局最优解的算法策略。其核心思想是通过局部最优解的累积逼近全局最优解,但需要注意贪心算法并不保证总能得到全局最优解,需结合问题特性分析。
贪心算法的适用条件
- 贪心选择性质:问题的全局最优解可以通过一系列局部最优选择得到。
- 最优子结构:问题的最优解包含其子问题的最优解。
贪心算法的实现步骤
- 将问题分解为若干子问题。
- 对每个子问题求解局部最优解。
- 将局部最优解合并为全局解。
经典问题示例
找零钱问题
给定不同面额的硬币和一个总金额,求最少硬币数组合。
#include <vector>
#include <algorithm>
using namespace std;int coinChangeGreedy(vector<int>& coins, int amount) {sort(coins.rbegin(), coins.rend()); // 降序排序int count = 0;for (int coin : coins) {while (amount >= coin) {amount -= coin;count++;}}return amount == 0 ? count : -1; // 若无法凑齐则返回-1
}
活动选择问题
选择最多的互不重叠活动(按结束时间排序)。
#include <vector>
#include <algorithm>
using namespace std;int maxActivities(vector<pair<int, int>>& activities) {sort(activities.begin(), activities.end(), [](auto& a, auto& b) {return a.second < b.second; // 按结束时间升序});int count = 1, last_end = activities[0].second;for (int i = 1; i < activities.size(); ++i) {if (activities[i].first >= last_end) {count++;last_end = activities[i].second;}}return count;
}
贪心算法的局限性
- 局部最优不保证全局最优:例如部分背包问题中,贪心可能无法得到最优解。
- 依赖问题特性:需严格证明贪心策略的正确性,例如霍夫曼编码问题。
贪心与动态规划的区别
- 贪心算法:无回溯,直接选择当前最优解。
- 动态规划:记录子问题的解,通过状态转移逐步求解。
实际应用场景
- 最小生成树(Prim、Kruskal算法)。
- 最短路径(Dijkstra算法)。
- 数据压缩(霍夫曼编码)。
通过合理选择贪心策略,可以高效解决许多优化问题,但需注意验证其正确性。