2.17*(second)

山东理工大学第八届ACM校赛——活动选择

最近打完了校赛 领完奖品以为就完事了 直到老师管我们要题解......当时比赛的时候一个题的代码都没存 然而老师的话又不能不听 于是我们三个经过商量之后 就愉快的把任务瓜分了 于是 我的任务就变成了一部分的简单题 难题和防AK题就交给他们了 这些代码是后来又重新敲的
有的跟比赛时提交的代码有些出入 但大体思路是一样的
首先A、B题 我感觉应该都没什么问题吧 因此这里直接敲C题的题解 首先来一发链接  活动选择
看到这个题的题干 很容易联想到C语言课本上的 活动选择问题 但这个题不同之处在于 它不是要求找出最多能举办多少活动 而是要求求出要举办所有活动所需的最少教室数 因此并不能用书上的方法求解
为了解决这个题 我们先来仔细分析一下题意
多组输入,每组输入一个n(1 <= n <= 100000)表示活动的数量,接下来的n行每行两个整数l,r(1
< l < r < 10^9)代表活动的开始时间与结束时间。
题目要求求出所需的最少教室数量 首先 我们知道 在一个教室正在举办活动的时候 如果又要举办一个活动 那就需要多占用一个教室 也就是说 当两个活动时间有重叠时 就需要多一个教室 因此最少需要的教室数量就是最多的同时举办的活动个数 也就是时间重叠的活动个数 
那么 这个个数要怎么求呢 可以用数组记录一下这些活动的开始与结束时间 
(以示例数据为例)

可以看到 在1-2、 3-4、 2-9是有活动的 而在3-4期间是同时有两个活动的 而其他时间是没有冲突的 因此需要至少两个教室
对于个数的计算 只要对数组进行一下处理 让计数变量每次遇到开始就自加一 每次遇到结束就自减一 然后整个过程中计数变量的最大值就是要求的最少教室数


先将数组在有活动开始或结束的地方进行+1/-1操作 最后再扫一遍数组 将整个数组处理成下面的图片的样子 因为若上一个活动的结束时间与下一个活动开始时间相同的话 两个活动不会冲突 因此在每个位置 先减去结束的 再加上开始的 整个过程中在3这个时间取到最大值2
答案也出来了 那么这个题是不是就这么结束了呢 当然不 我们来仔细看一下题目给的数据范围 时间是到10的九次方的(不要问我为什么会有那么多时间 可能这些时间以10的负五次方为单位吧) 如果开一个十的九次方的数组 然后对这个数组进行操作 不管是时间还是内存都是撑不住的 那么要怎么办呢 
这时候 我们注意到 活动的数量只到十万 这是个完全撑得住的数量 而我们对数组进行操作的时候 其实并不会注意当前时间是多少 而只需要关心这些时间之间的相对位置即可 只要有一个活动结束时间在下一个活动的开始时间之后 就需要多一间教室 其他情况同理 
因此 只需要存下这些时间的相对位置 当然 由于没有直接存到数组里 这些时间并不一定有序 这时候就需要进行排序 排序方法可以是自己手敲的快排 也可以是STL里的快排 但是注意不要使用冒泡排序 因为十万的平方的排序复杂度会超时的
#include <stdio.h>
#include <algorithm>

using namespace std;

struct act
{
	bool f;//f用来判断是开始时间还是结束时间
	int t;
}a[222222];//数组开题目范围两倍 因为开始和结束时间分开来存

bool heh(struct act a, struct act b)
{
	if (a.t==b.t) return a.f > b.f;//如果时间相同 则结束的排在开始的前面
	return a.t < b.t;//若时间不同 按时间升序排序
}

int main()
{
	int n, i;
	while (~scanf("%d", &n))
	{
		for (i = 0; i < n * 2; i += 2)
		{
			scanf("%d%d", &a[i].t, &a[i+1].t);
			a[i].f = 0;
			a[i+1].f = 1;
		}
		sort(a, a+n*2, heh);
		int l = 0, h = 0;
		for (i = 0; i < n * 2; i++)
		{
			if (a[i].f == 0) l++;//l是当前时间的活动数量
			else l--;
			h = h>l ? h : l;//h是整个过程中最大的活动数量
		}
		printf("%d\n", h);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/beposit/article/details/79333537