描述:

一个新学期来临了,学生们烦恼与选课。学生们在网络课程系统上面选课。那里有n门课,第i门课准许在时间间隔(Ai,Bi)内选择。那意味着,如果你想选第i门课,你必须在时间Ai之后和Bi之前选择它。Ai和Bi全部用分钟表示。一个学生只能每5分钟选一次课,但是他可以选择在任意时间开始选课,还有可以尝试任意多次。例如,如果你尝试在5分21秒时选课,那么你可以在10分21秒,15分21秒,20分21秒…时继续尝试。一个学生不能在同一时间选择多于一门的课。可能会发生有一个学生在尝试选课时却发现已经无课可选的情况。

请你来计算下一个学生至多能选多少门课。

输入:

不超过100组测试数据。

每组测试数据的第一行包含一个整数N。N是课程的数量 (0 < N <= 300) 。

接下来有n行。每行包含两个整数Ai和Bi (0 <= Ai < Bi <=1000),表示第i门课准许在时间间隔(Ai,Bi)内选择。

当N=0时表示输入停止。

输出:

对于每组测试数据,用一行输出一个整数,表示一个学生最多能选课程的数量。

思路:

本题思路为贪心。

简单思考可知,选课共有5种方案,分别为:在时间范围(5*k+0,5*k+1),(5*k+1,5*k+2),(5*k+2,5*k+3),(5*k+3,5*k+4),(5*k+4,5*k+5)内开始选课。

我们可以通过枚举5种方案再配合贪心思想得出正确答案。本题的贪心思想主要体现在选课的优先顺序上,优先选择结束时间早的课程。这是非常好理解的,先选了结束时间早的课程,那么结束时间晚的课程可能还有机会在下次选课时被选上,就算选不上,那也只能说明鱼和熊掌不可兼得。

代码:

#include<iostream>
#include<stdio.h>
using namespace std;
struct point
//将课程的时间范围封转在结构体中,便于利用qsort排序。 
{
	int a;
	//开始时间 
	int b;
	//结束时间 
}course[300];
int n;
int max(int a,int b) 
{
	return a>b?a:b;
}
int min(int a,int b)
{
	return a<b?a:b;
}
int cmp(const void* m,const void* n)
//比较函数,将课程按照结束时间由早到晚排序。 
{
	return (*(point*)m).b-(*(point*)n).b;
}
int solve(int start,int min_a,int max_b)
//start的值只可以为0、1、2、3、4。 
//min_a为所有课程中开始时间的最小值。
//max_b为所有课程中结束时间的最大值。 
{
	bool mark[300];
	//mark[]用于标记某节课是否被选过。 
	for(int i=0;i<n;i++)
		mark[i]=false;
	int sum=0;
	//选课数量。 
	for(int i=min_a/5*5+start;i<max_b;i+=5)
	//[0,min_a/5*5)范围内不会有课程可以选。 
		for(int j=0;j<n;j++)
			if(!mark[j]&&course[j].a<=i&&i<course[j].b)
			//遇见的第一个没被标记过且可选的课程。
			//这也意味着此课程是此时可选课程里结束时间最早的。
			//优先选择结束时间最早的课程的现实意义是,结束时间较晚的课程可能还有机会在下次选课时被选中。 
			{
				mark[j]=true;
				sum++;
				break;
			}
	return sum;
}
int main()
{
	while(scanf("%d",&n)&&n)
	{
		int min_a=1000,max_b=0;
		for(int i=0;i<n;i++)
		{
			scanf("%d%d",&course[i].a,&course[i].b);
			min_a=min(min_a,course[i].a);
			max_b=max(max_b,course[i].b);
		}
		qsort(course,n,sizeof(course[0]),cmp);
		int res=0;
		for(int i=0;i<5;i++)
			res=max(res,solve(i,min_a,max_b));
		printf("%d\n",res);
	}
}