题解
突飞猛进
1 条题解
-
0
P4797 突飞猛进(入门)
解题思路
-
读懂题目:只有一间会议室,给出 n 个作战会议的开始时间和结束时间,问一天里最多能安排多少个会议。注意:两个会议之间不需要准备时间,一个会议结束,另一个可以立即开始(也就是前一个的结束时间等于后一个的开始时间也可以接上)。
-
打个比方:就像课间抢篮球场,球场只有一个,每支队伍用一段时间。想在一节课间里多打几场,就要尽量选"结束早"的场次——越早结束,留给后面的时间越多。
-
贪心结论:把所有会议按"结束时间从早到晚"排序,然后从左到右扫描:第一个会议必选,之后每个会议只要它的开始时间不早于上一个已选会议的结束时间,就选它。
-
为什么按结束时间排序:一场会议越早结束,后面的安排空间越大。如果先选了一个结束很晚的会议,它可能挤掉好几场本可以安排的短会议。所以"每次选结束最早的、时间不冲突的会议"是最优的,这就是经典的"区间调度"贪心。
-
看例子:样例会议 (8,13),(2,11),(7,9),(13,16),(3,8),按结束时间排序为 (3,8),(7,9),(2,11),(8,13),(13,16)。先选 3-8;再看 7-9,开始 7 早于 8,冲突不选;2-11 开始 2 早于 8,不选;8-13 开始 8 等于 8,可以接上,选它;13-16 开始 13 等于 13,选它。共 3 个会议。
-
边界情况:结束时间等于开始时间时可以接上(用 >= 判断);如果两个会议时间完全一样,只能选其中一个。
参考代码
// P4797 突飞猛进:按会议结束时间排序,优先选结束早的,可开的会议最多 #include <iostream> #include <algorithm> using namespace std; struct Meeting { int start; int end; }; // 会议的开始时间和结束时间 Meeting meetings[1005]; // 比较函数:结束时间早的在前,相同则开始时间早的在前 bool cmp(const Meeting& a, const Meeting& b) { if (a.end != b.end) return a.end < b.end; return a.start < b.start; } int main() { int n; cin >> n; for (int i = 0; i < n; i++) cin >> meetings[i].start >> meetings[i].end; sort(meetings, meetings + n, cmp); int count = 1; // 已选择的会议数,第一个必选 int lastEnd = meetings[0].end; // 上一个会议结束的时间 for (int i = 1; i < n; i++) { if (meetings[i].start >= lastEnd) { // 这个会议在上一场结束后开始,可以安排 count++; lastEnd = meetings[i].end; } } cout << count << endl; return 0; }复杂度分析
排序用 sort 函数,时间复杂度 O(n log n);排序后扫描一遍会议是 O(n)。n≤1000,运算量极小。空间上用了长度 1005 的结构体数组,是 O(n)。这是区间调度问题的标准解法,掌握它就能解决"最多安排几场活动"这一类问题。
-
- 1