题解:洛谷 P6244 Country Fair Events
【题目来源】
洛谷:P6244 [USACO06OPEN] County Fair Events S - 洛谷
【题目描述】
FJ 参加活动。
他想参加尽可能多的 \(N\) 个活动,参加完某个之后可以立刻参加下一个。
给定 FJ 可参加的活动列表、其开始时间 \(T\) 和持续时间 \(L\) ,求 FJ 可以参加的最大活动数。
FJ 每个活动都不会提早离开。
【输入】
第一行有一个整数 \(N\)。
第二到 \(N+1\) 行:每行包含两个用空格分隔的整数 \(T\) 和 \(L\) ,意义如上述。
【输出】
输出仅一行,FJ 最多能参加几个活动。
【输入样例】
7
1 6
8 6
14 5
19 2
1 8
18 3
10 6
【输出样例】
4
【核心思想】
-
问题分析:给定 \(N\) 个活动的开始时间 \(T\) 和持续时间 \(L\),求最多能参加多少个互不重叠的活动。本质上是经典区间调度贪心问题:按结束时间排序,每次选择结束最早且不与已选活动冲突的活动。
-
算法选择:
- 贪心排序:按活动结束时间升序排序
- 贪心选择:维护上一个选中活动的结束时间
last,选择开始时间 \(\geq\)last的最早结束活动
-
关键步骤:
- 读取数据:读入 \(N\) 和 \(N\) 个活动的 \((T, L)\),计算结束时间 \(end = T + L\)
- 排序:按
end升序排列 - 贪心选择:
- 初始化
last = p[1].end,ans = 0 - 遍历 \(i = 2\) 到 \(N\):
- 若 \(p[i].start \geq last\):选中该活动,
ans++,last = p[i].end
- 若 \(p[i].start \geq last\):选中该活动,
- 初始化
- 输出
ans + 1(加上第一个活动)
-
时间/空间复杂度:
- 时间复杂度:\(O(N \log N)\),排序主导
- 空间复杂度:\(O(N)\),存储活动信息
-
区间调度贪心的核心思想:
- 结束时间优先:选择结束最早的活动,为后续活动留出更多时间,这是区间调度问题的经典最优策略
- 交换论证:假设最优解中第一个活动不是结束最早的,用结束更早的活动替换不会减少可选活动数
- 不相交判定:两个活动相容当且仅当后一个的开始时间 \(\geq\) 前一个的结束时间
- 与动态规划的对比:贪心 \(O(N \log N)\) 远优于 DP 的 \(O(N^2)\),但仅适用于"最大化活动数"目标
- 适用于活动选择、区间调度、资源分配类问题
【解题思路】

【算法标签】
普及- #贪心
【代码详解】
#include <bits/stdc++.h>
using namespace std;
int n, ans=0;
struct node {
int start ,end;
}p[10005];
bool cmp(node a, node b)
{
return a.end<b.end;
}
int main()
{
cin >> n; // 输入n
for (int i=1; i<=n; i++) { // 遍历n个活动
int tmp;
cin >> p[i].start >> tmp; // 记录起始时间
p[i].end = p[i].start+tmp; // 并计算结束时间
}
sort(p+1, p+n+1, cmp); // 按照结束时间从小到大排序
int last = p[1].end; // 定义last为第一个活动的结束时间
for (int i=2; i<=n; i++) { // 从第2个活动开始遍历
if (p[i].start>=last) { // 如果其起始时间在上个结束时间之后
ans++; // 就可以参加
last = p[i].end; // 更新结束时间为本活动结束时间
}
}
cout << ans+1 << endl; // 输出结果,加上的1为第1个活动
return 0;
}
【运行结果】
7
1 6
8 6
14 5
19 2
1 8
18 3
10 6
4
浙公网安备 33010602011771号