C++ 的贪心算法(Greedy Algorithm)是一种在每一步选择中都做出当前最优解(局部最优),希望最终能得到全局最优解的算法策略。贪心算法适用于最优子结构和贪心选择性质的问题。
贪心算法的基本步骤
- 排序(若必要):根据贪心策略对数据进行排序。
- 贪心选择:在当前状态下选择最优解。
- 可行性检查(若必要):确保选择符合问题约束。
- 重复执行,直到所有选择完成。
C++ 贪心算法示例
示例 1:活动选择问题(区间调度问题)
问题描述:有 n 个活动,每个活动都有起始时间 start[i]
和结束时间 end[i]
,每次只能选择一个活动,求最多能安排多少个互不冲突的活动。
贪心策略:每次选择最早结束的活动,这样可以留给后面的活动更多的时间。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// 活动结构体
struct Activity {
int start, end;
};
// 按结束时间排序
bool compare(Activity a, Activity b) {
return a.end < b.end;
}
int maxActivities(vector<Activity> &activities) {
sort(activities.begin(), activities.end(), compare); // 按结束时间排序
int count = 1, last_end = activities[0].end;
for (int i = 1; i < activities.size(); i++) {
if (activities[i].start >= last_end) { // 如果活动开始时间不冲突
count++;
last_end = activities[i].end;
}
}
return count;
}
int main() {
vector<Activity> activities = {{1, 3}, {2, 5}, {3, 9}, {6, 8}, {5, 7}};
cout << "最多可以安排的活动数: " << maxActivities(activities) << endl;
return 0;
}
时间复杂度:O(nlogn)O(n \log n)(排序占主导)
示例 2:最小零钱找零
问题描述:给定若干面额的硬币,如何用最少的硬币找零 amount
?
贪心策略:优先使用面值最大的硬币。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int minCoins(vector<int> &coins, int amount) {
sort(coins.rbegin(), coins.rend()); // 按面值从大到小排序
int count = 0;
for (int coin : coins) {
while (amount >= coin) {
amount -= coin;
count++;
}
}
return count;
}
int main() {
vector<int> coins = {1, 5, 10, 25};
int amount = 63;
cout << "最少硬币数: " << minCoins(coins, amount) << endl;
return 0;
}
注意:贪心算法不一定适用于所有找零问题,比如硬币面额 {1, 3, 4}
找 6
时,贪心会选择 {4, 1, 1}
(3枚),但最优解是 {3, 3}
(2枚)。
贪心算法的适用场景
- 区间问题(活动安排、区间覆盖)
- 最小代价问题(Huffman 编码、最小生成树)
- 排序优化(最优任务调度)
- 贪心找零(但要小心无法保证全局最优)
总结:贪心算法在部分问题上能得到最优解,但不能保证所有问题都适用,使用前要确保满足贪心选择性和最优子结构。&