🌟《贪心王国·打点小精灵大作战》
🏰 一、故事开场
在贪心王国里,有一片神秘的区域森林 🌲
森林里有很多“魔法区间”,比如:
👉 [1,5]
👉 [2,6]
👉 [4,7]
😈 危机来了!
每个区间里都有怪物 👾
国王下令:
⚠️ 每个区间,必须至少放2个守护点!
🧙♂️ 小勇士的任务
👉 放尽量少的点
👉 但要满足:每个区间 ≥ 2个点
🧠 二、让学生思考
汉克老师问:
👉 点放在哪里比较好?
🎯 学生纷纷说:
放左边?
放中间?
放右边?
💡 三、关键发现(贪心思想)
汉克老师说:
👉 如果你把点放在右边……
👉 会不会更容易被后面的区间用到?
🎉 结论!
🌟点尽量往右放!
🧪 四、一起玩一个例子
区间:
[1,4] [2,5] [3,6]🪄 第一步:排序(按右边)
👉 已经排好了:
[1,4] → [2,5] → [3,6]🧙♂️ 第二步:处理第一个区间
👉 [1,4] 需要 2 个点!
我们放:
👉 3 和 4(靠右!)
🎯 现在发生什么?
这两个点:
在 [1,4] ✔
在 [2,5] ✔
在 [3,6] ✔
😲 结果!
👉 后面两个区间也被“顺便解决了”!
🎉 五、最终答案
👉 只用了2个点!
🧠 六、总结规律
1、🌟 核心策略
👉每次补点,都往区间右边放!
2、🌟 为什么?
👉 因为:
🌟 越靠右 → 越容易帮助后面的区间!
🪄 七、算法步骤
✅ 第1步:排序(按右端点)
👉 谁结束早,先处理谁
✅ 第2步:一个区间一个区间看
✅ 第3步:如果这个区间不够2个点
👉 就补点!
✅ 第4步:补在哪里?
👉 放在:
right
right-1
✅ 第5步:这些点可以“帮助后面的区间”
💻 八、参考程序
#include <iostream> #include <algorithm> using namespace std; // 定义区间 struct Interval { int left; // 左端点 int right; // 右端点 int need; // 还需要几个点(初始为2) }; // 排序规则:按右端点从小到大 bool cmp(Interval a, Interval b) { if (a.right != b.right) return a.right < b.right; else return a.left < b.left; } int main() { int n; cin >> n; Interval a[10005]; // 输入 for (int i = 0; i < n; i++) { cin >> a[i].left >> a[i].right; a[i].need = 2; // 每个区间需要2个点 } // 排序 sort(a, a + n, cmp); int answer = 0; // 选了多少个点 // 遍历每个区间 for (int i = 0; i < n; i++) { // 如果这个区间还缺点 while (a[i].need > 0) { // 我们选择点:优先选右端点 int chosen_point; if (a[i].need == 2) chosen_point = a[i].right - 1; // 第一个点 else chosen_point = a[i].right; // 第二个点 answer++; // 选了一个点 // 用这个点去“帮助”后面的区间 for (int j = i; j < n; j++) { if (a[j].left <= chosen_point && chosen_point <= a[j].right) { if (a[j].need > 0) a[j].need--; } } } } cout << answer << endl; return 0; }💣 八、最容易犯错的地方
❌ 错误1:点放左边
👉 ❌ 很亏!
👉 后面用不到
❌ 错误2:不排序
👉 ❌ 会乱!
👉 贪心会失败
❌ 错误3:忘记“要2个点”
👉 ❌ 有学生只放1个
❌ 错误4:不会“共享点”
👉 ❌ 以为每个区间都要重新放
👉 实际:
🌟 一个点可以帮多个区间!
🎮 九、课堂小游戏
🎯 游戏1:你来放点!
区间:
[1,3] [2,4] [3,5]👉 学生们:
👉 你会放哪里?
🎯 游戏2:对比
👉 放左边 vs 放右边
👉学生发现:
👉右边更强!
🎯 十、背诵口诀
👉区间要点多,全部往右挪!
👉越靠右越值钱!
🎉 十一、本课总结
同学们终于学会了:
✨ “最强打点术!”
同学们发现:
🌟 一个点,不只是一个点
🌟 而是可以影响很多区间!
汉克老师笑着说:
“这就是贪心的智慧——用最少的资源,做最多的事情。”