贪心算法双剑合璧:C++与Python征服洛谷三大经典问题

目录

🌟 贪心算法核心思想

📌 题目一:P1223 排队接水(时间调度)

题目描述

解题思路

代码实现

📌 题目二:P1803 凌乱的yyy / 线段覆盖(区间调度)

题目描述

解题思路

代码实现

📌 题目三:P1090 合并果子(优先队列)

题目描述

解题思路

代码实现

💡 贪心算法四步心法

🚨 常见问题与避坑指南

🌐 实战扩展(LeetCode真题)


🌟 贪心算法核心思想

局部最优 → 全局最优 → 贪心选择性质 → 无后效性
本文精选洛谷贪心题单中三大经典问题,通过C++与Python双语言对比实现,彻底掌握贪心策略的精髓!


📌 题目一:P1223 排队接水(时间调度)

题目描述

n个人排队接水,第i个人接水时间为t[i],求最小平均等待时间。

解题思路
  1. 贪心策略:按接水时间升序排序

  2. 数学证明:短任务优先可最小化总等待时间


代码实现

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个比赛时间段,选择最多不重叠比赛。

解题思路
  1. 贪心策略:按结束时间升序排序

  2. 遍历选择:每次选最早结束且不与已选冲突的区间


代码实现

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 合并果子(优先队列)

题目描述

每次合并两堆果子消耗体力值为两堆之和,求最小总消耗。

解题思路
  1. 贪心策略:每次合并最小的两堆(哈夫曼编码思想)

  2. 数据结构:小根堆/优先队列高效获取最小值


代码实现

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)

💡 贪心算法四步心法

  1. 问题分析:识别是否具有贪心选择性质

  2. 策略设计:确定局部最优的选择方式

  3. 正确性证明:数学归纳法/反证法验证

  4. 实现优化:选择合适的数据结构加速


🚨 常见问题与避坑指南

问题解决方案
策略错误反例验证策略正确性(如P1223反序验证)
优先队列方向错误C++默认大根堆,需指定greater<int>
区间端点处理错误确认是否包含端点(闭区间/开区间)

🌐 实战扩展(LeetCode真题)

  1. 455. 分发饼干 → 双指针贪心

  2. 435. 无重叠区间 → 同P1803

  3. 1167. 连接木棍的最低成本 → 类似P1090


🔥 关注我,算法能力指数级提升!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值