一、活动调度问题
题目:
假设要用很多个教室对一组活动进行调度。我们希望使用尽可能少的教室来调度所有的活动。
输入要求:
第一行为活动的个数 N(1<=N<=1 000 000) 。
接下来 N 行为 Si 和 Fi(0<=Si<Fi<=2 000 000 000) ,分别代表第 i 个活动的开始时间和结束时间。活动 i 的区间段为 [Si,Fi)
输出要求:
输出有一行 M ,为所需教室的最小数量。
测试输入:
11
1 4
3 5
0 6
5 7
3 8
5 9
6 10
8 11
8 12
2 13
12 14
测试输出:
5
思路
首先,按照贪心的思路,将输入的用例按照结束时间从早到晚进行排序(巧合的是给出的测试用例已经按照这个规则排好了,但我不能保证其他的用例也是这样,所以还是贪心排序了一次)
其次,从第一个活动开始做循环。
记当前的活动为i,循环碰到的下一个活动为j,如果j活动的开始时间晚于或等于i活动,那么就找到了第一种组合方式的开端,如果不满足条件,则j+1记为j继续循环,如此找完一组之后,返回一个1给记录总组数的sum变量。
注意,为了防止某一个被用过的时间段在后续被重复调用,我们需要一个数组来记录哪些活动已经被使用过了,在代码中我使用了times数组。
最后,往复循环这个过程,得到sum值,输出。
#include <iostream>
using namespace std;
int num;
int start[1000000] = { 0 };
int finish[1000000] = { 0 };
int times[1000000] = { 0 };
void Initial()//初始化,进行输入
{
cin >> num;
for (int i = 0; i < num; i++)
{
cin >> start[i];
cin >> finish[i];
}
}
void Rank()//贪心排序,使用了冒泡排序法,归并排序应该更快些,但是现在忘了
{
for (int i = 0; i < num - 1; i++) {
for (int j = i; j < num - 1 - i; j++) {
if (finish[j] > finish[j + 1]) {
int s = start[j], f = finish[j];
start[j] = start[j + 1];
finish[j] = finish[j + 1];
start[j + 1] = s;
finish[j + 1] = f;
}
}
}
}
int Find(int x)//最重要的分组环节
{
if (times[x] == 1)//如果通过查找记录数组,发现该活动已经使用,则返回0
return 0;
int i = x;
bool flag = true;//flag用于将每个分组的最后一个活动在记录数组中对应的值,置零
while ( i < num ) {
for (int j = i + 1; j < num; j++) {
if (start[j] >= finish[i] && times[j] == 0) {
times[j] = 1;
i = j;
flag = true;
break;
}
else
flag = false;
}
if (i == num - 1) {
flag = false;
}
if (flag == false) {
times[i] = 1;
break;
}
}
return 1;
}
int main()
{
Initial();
Rank();
int sum = 0;
for (int i = 0; i < num; i++) {
sum += Find(i);
}
cout << sum << endl;
return 0;
}