hrbust 1539 选课【思维+贪心】好题

选课
Time Limit: 1000 MSMemory Limit: 65535 K
Total Submit: 63(21 users)Total Accepted: 21(17 users)Rating: Special Judge: No
Description

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

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

Input

不超过100组测试数据。

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

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

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

Output

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

Sample Input
2
1 10
4 5
0
Sample Output
2

题目大意:

为什么中文题也要写出中文题意呢,因为这个题只有语文好的才能一遍读懂。


一个学生,必须每间隔五分钟就去选一次课,不能间隔6分钟,而且要注意题目给出的范围、可选课范围是:(Ai,Bi)是开区间。虽然给出的是分钟,但是我们可以在某一秒去选课。


思路:

1、对于开区间的解决方法:其实不难,对于当前走到的时间now,if(now>=a[i].x&&now<a[i].y)就能够搞定这个问题。

给出一组这块可能Wa的数据:

2

1 2

7 8

应该输出1,因为在开区间中,第一个区间无论在哪一秒选课,都不可能过五分钟的时候选到第二个课程。


2、因为时间是必须间隔五分钟选一次课,其实那么问题也就简单化了,我们枚举起点时间,每一轮选完课程之后,时间+5,继续判断即可。那么这个枚举的时间起点是从0---1000吗?显然这样做就会超时。O(T*1000/5*N)。

我们考虑这样一个问题,起点为1和起点为6是否是一个含义呢?当然不是一个含义,但是以1作为起点一定包含6,但是以6作为起点是一定不包含1的,所以其实枚举起点,我们只需要枚举0、1、2、3、4作为起点就够了,那么时间复杂度降到:O(T*4*N);


3、注意每一轮选课只能选一门,不能多选。


4、那么这个时候暴力枚举是不是就OK了呢?明显还是不够谨慎,我们在选课的时候,每一轮每一个时间选哪门课都是有最优方案的,所以这里要加上贪心的思路。


5、辣么要如何贪心呢?我们希望早结束选课的课程先选上,所以排序的时候按照结束的时间从小到大排序。如果结束时间相同,我们希望早开始的课程先选上。


6、整体思路构成,即枚举起点时间+贪心排序+枚举选课。


Ac代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
struct node
{
    int x,y;
}a[100000];
int vis[5000];
int cmp(node a,node b)
{
    if(a.y==b.y)return a.x<b.x;
    else return a.y<b.y;
}
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        if(n==0)break;
        for(int i=0;i<n;i++)
        {
            scanf("%d%d",&a[i].x,&a[i].y);
        }
        int output=0;
        sort(a,a+n,cmp);
        for(int i=0;i<=4;i++)
        {
            memset(vis,0,sizeof(vis));
            int now=i;
            int cont=0;
            while(1)
            {
                for(int j=0;j<n;j++)
                {
                    if(a[j].x<=now&&now<a[j].y)
                    {
                        if(vis[j]==0)
                        {
                            vis[j]=1;
                            cont++;
                            break;
                        }
                    }
                }
                now+=5;
                if(now>=1010)break;
            }
            output=max(output,cont);
        }
        printf("%d\n",output);
    }
}




  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值