活动调度/活动安排(超详细)
输入要求
第一行为活动的个数 N(1<=N<=1 000 000) 。
接下来 N 行为 Si 和 Fi(0<=Si<Fi<=2 000 000 000) ,分别代表第 i 个活动的开始时间和结束时间。活动 i 的区间段为 [Si,Fi)
输出要求
输出有一行 M ,为所需教室的最小数量。
样例
input
11
1 4
3 5
0 6
5 7
3 8
5 9
6 10
8 11
8 12
2 13
12 14
output
5
题解
求最大相容活动的详解可以参考以下博客
https://blog.csdn.net/ii1245712564/article/details/45420061
https://blog.csdn.net/cyp331203/article/details/43199963
本题为求最少需要的教室数,相当于将所给集合g划分成几个子集合,每个集合都尽量容纳更多的相容活动。
解题方法:
以题目样例为例子,推导过程如下:
- 先将开始时间和结束时间分别从小到大排序。这一步至关重要!
- 将排好序的活动按顺序从头开始访问,如果开始时间小于最小的结束时间,那么只能新开一个教室,将该活动分配至教室1,该例子中将活动(0,6)分配到教室1,接着访问下一个活动开始时间,如果它仍然小于最小结束时间,新开教室,该例中依次将活动(1,4)、(2,13)、(3,5)、(3,8)放入教室2、3、4、5。
- 继续访问下一个活动开始时间,如果大于或者等于最小的结束时间,那么这个活动就可以放在结束时间最小的活动后面,即将(5,7)放入教室2。
- 依次类推,最后即可得最少所需教室数。
代码
如何编程实现以上思路呢?
可以设置一个计数器和一个变量记录这个过程中计数器的最大值。当开始时间小于结束时间,表示这个活动需要新开教室(注意已将时间排好序),计数器加一,如果开始时间大于或等于结束时间,说明不需要新开教室,直接将这个活动加入到这个结束时间的活动后面即可,因为是记录计数器的最大值,所以让计数器减一,依次往下,最后计数器最大值即为答案。
#include<iostream>
#include<algorithm>
#define N 1000005
using namespace std;
int s[N], t[N];
int main() {
int cnt = 0;//计数器
int ans = 0;
int i, j;//游标
int n;
cin >> n;
for (i = 0; i < n; i++) {
cin >> s[i] >> t[i];
}
sort(s, s + n);
sort(t, t + n);
i = 0;
j = 0;
while (i < n && j < n) {
//开始时间小于当前最小结束时间
if (s[i] < t[j]) {
cnt++;
i++;//游标移到下一个活动(开始时间列上的活动)
ans = max(ans, cnt);
}
//开始时间大于当前最小结束时间
else if (s[i] > t[j]) {
cnt--;
j++;//游标移到下一个活动(结束时间列上的活动)
}
//开始时间等于当前最小结束时间
else {
j++;
i++;//两个游标同时移动,计数器不动
}
}
cout << ans << endl;
}