目录
📌 题目二:P1803 凌乱的yyy / 线段覆盖(区间调度)
🌟 贪心算法核心思想
局部最优 → 全局最优 → 贪心选择性质 → 无后效性
本文精选洛谷贪心题单中三大经典问题,通过C++与Python双语言对比实现,彻底掌握贪心策略的精髓!
📌 题目一:P1223 排队接水(时间调度)
题目描述
n
个人排队接水,第i
个人接水时间为t[i]
,求最小平均等待时间。
解题思路
-
贪心策略:按接水时间升序排序
-
数学证明:短任务优先可最小化总等待时间
代码实现
C++版(排序优化)
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
int n;
cin >> n;
vector<pair<int, int>> t(n);
for(int i=0; i<n; ++i) {
cin >> t[i].first;
t[i].second = i+1;
}
sort(t.begin(), t.end());
double total = 0, current = 0;
for(auto &p : t) {
total += current;
current += p.first;
}
printf("%.2f", total / n);
return 0;
}
Python版(极简实现)
n = int(input())
t = list(map(int, input().split()))
t_sorted = sorted((val, idx+1) for idx, val in enumerate(t))
total, current = 0.0, 0.0
for time, _ in t_sorted:
total += current
current += time
print("{:.2f}".format(total / n))
📌 题目二:P1803 凌乱的yyy / 线段覆盖(区间调度)
题目描述
给定n
个比赛时间段,选择最多不重叠比赛。
解题思路
-
贪心策略:按结束时间升序排序
-
遍历选择:每次选最早结束且不与已选冲突的区间
代码实现
C++版(结构体排序)
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
struct Event { int start, end; };
int main() {
int n;
cin >> n;
vector<Event> events(n);
for(auto &e : events) cin >> e.start >> e.end;
sort(events.begin(), events.end(), [](auto &a, auto &b) {
return a.end < b.end;
});
int count = 0, last_end = 0;
for(auto &e : events) {
if(e.start >= last_end) {
count++;
last_end = e.end;
}
}
cout << count;
return 0;
}
Python版(元组排序)
n = int(input())
events = [tuple(map(int, input().split())) for _ in range(n)]
events.sort(key=lambda x: x[1])
count, last_end = 0, 0
for start, end in events:
if start >= last_end:
count += 1
last_end = end
print(count)
📌 题目三:P1090 合并果子(优先队列)
题目描述
每次合并两堆果子消耗体力值为两堆之和,求最小总消耗。
解题思路
-
贪心策略:每次合并最小的两堆(哈夫曼编码思想)
-
数据结构:小根堆/优先队列高效获取最小值
代码实现
C++版(priority_queue)
#include <iostream>
#include <queue>
using namespace std;
int main() {
int n, x, ans = 0;
priority_queue<int, vector<int>, greater<int>> pq;
cin >> n;
while(n--) {
cin >> x;
pq.push(x);
}
while(pq.size() > 1) {
int a = pq.top(); pq.pop();
int b = pq.top(); pq.pop();
ans += a + b;
pq.push(a + b);
}
cout << ans;
return 0;
}
Python版(heapq模块)
import heapq
n = int(input())
heap = list(map(int, input().split()))
heapq.heapify(heap)
ans = 0
while len(heap) > 1:
a = heapq.heappop(heap)
b = heapq.heappop(heap)
ans += a + b
heapq.heappush(heap, a + b)
print(ans)
💡 贪心算法四步心法
-
问题分析:识别是否具有贪心选择性质
-
策略设计:确定局部最优的选择方式
-
正确性证明:数学归纳法/反证法验证
-
实现优化:选择合适的数据结构加速
🚨 常见问题与避坑指南
问题 | 解决方案 |
---|---|
策略错误 | 反例验证策略正确性(如P1223反序验证) |
优先队列方向错误 | C++默认大根堆,需指定greater<int> |
区间端点处理错误 | 确认是否包含端点(闭区间/开区间) |
🌐 实战扩展(LeetCode真题)
-
455. 分发饼干 → 双指针贪心
-
435. 无重叠区间 → 同P1803
-
1167. 连接木棍的最低成本 → 类似P1090
🔥 关注我,算法能力指数级提升!