P1167 刷题

题目描述

NOIP 临近了,小 A 却发现他已经不会写题了。好在现在离竞赛还有一段时间,小A决定从现在开始夜以继日地刷题。也就是说小 A 废寝忘食,一天二十四小时地刷题。

今天的日期(时间)是 yyyy 年 mm 月 dd 日 hh 时 min 分,考试的时间是 yyyy2 年 mm2 月 dd2 日 hh2 时 min2 分。这之间的所有时间小 A 都用来刷题了,那么考试之前他最多能刷多少题呢?注意哦,考虑闰年。

时间紧张小A只管数量不管质量。当然有的题目容易一些,有的题目难一些。根据小A的经验,他能一眼看出写出某一个题目需要的时间,以分钟记。

现在给出洛谷 Online Judge 的题目列表,请你挑出最多的题目使小A能在竞赛前写出来。

我们假设从远古到未来,历法的表示与现在一样。

输入格式

第一行一个整数N,表示洛谷Online Judge的题目数,N≤5000

接下来N行,每行一个整数表示刷该题需要用的时间,以分钟记(10000)。(这个题本身是什么并不重要,不是么?小A已经写过题目数为00个)。

接下来两行依次是当前时间和竞赛时间。时间给出的格式是:yyyy-mm-dd-hh:min,例如:2007-06-23-02:00,采用24小时制,每天从00:00  23:59,年份从0000到9999

输出格式

一行,一个整数,noip前最多刷的题目数。

输入输出样例

输入 #1
2
1
1
2007-06-23-11:59
2007-06-23-12:00
输出 #1
1

首先,我们采取贪心策略.也就是说,将题目花费时间从大到小排序,先挑时间短的,接着依次往长里挑选,直到超时。
最大的问题是,如何计算分钟数?输入的是两个精确日期,不能直接相减,怎么变成分钟数?
我一直认为,像日期(包括年月日)、向量(大小和方向)、学生(包括姓名、学号、身高等)此类数据的集合体,最好用结构体实现。
struct _time
{
    int year;
    int month;
    int day;
    int hour;
    int minute;
}start,finish;//要求输入的起止时间

注意这里的结构体名称没有直接用“time”,而是加了下划线。这是因为C++本来就在某个头文件里有time的定义,再定义time会冲突。这个特性坑了我好几次,每次我用“max”来表示一个什么最大值时,都会产生错误“the reference to 'max' is ambiguous”(对max的引用不明确),大概就是因为这个。

然后,我们可以以公元1年1月1日0:00作为起点,计算某个日期与它相差的天数。这里我写的函数是从我早期刚开始接触C++时编写的一个计算星期的程序里复制下来的。

int totalDays(int year, int month, int day)
{
    int a;//当年已过的天数
    int leapYear = year / 4 - year / 100 + year / 400;//闰年的总数
    switch (month)
    {
    case 1:
        a = 0;
        break;
    case 2:
        a = 31;
        break;
    case 3:
        a = 31 + 28;//总感觉应该根据是不是闰年而判断加28还是29,但是程序输出总是正确的,不知道这是不是一个bug。
        break;
    case 4:
        a = 31 + 28 + 31;
        break;
    case 5:
        a = 31 + 28 + 31 + 30;
        break;
    case 6:
        a = 31 + 28 + 31 + 30 + 31;
        break;
    case 7:
        a = 31 + 28 + 31 + 30 + 31 + 30;
        break;
    case 8:
        a = 31 + 28 + 31 + 30 + 31 + 30 + 31;
        break;
    case 9:
        a = 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31;
        break;
    case 10:
        a = 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30;
        break;
    case 11:
        a = 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31;
        break;
    case 12:
        a = 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30;
        break;
    }
    return 365 * (year - 2 - leapYear) + leapYear*366 + a + day;//从公元1年1月1日到现在的天数
    /*减2是因为,已经过去的年没有公元0年,且也不包括用户输入的年份。减去闰年数量是因为闰年单算(乘以366)。所以,“year-2-leapYear”就是平年年数。变量a存储了用户输入年份
    之前,当年已经过的月份的天数*/
}

天数确定了,接下来就要将天数转化为分钟数,然后根据输入的两个日期,减去或加上一个分钟数,得到的就是我们梦寐以求的刷题时间了。

int mm(_time bef,_time aft)//计算两个日期分钟差距(不是绝对值)
{
    int _min;
    int _min_bef=bef.hour*60+bef.minute;
    int _min_aft=aft.hour*60+aft.minute;
    _min=_min_aft-_min_bef;
    return _min;
}

然后就是主程序:

int main()
{
//    freopen("P1167.txt","r",stdin); 
    cin>>N;
    for(int i=0;i<N;i++)
    {
        cin>>p[i];//每个题目用时
    }
    sort(p,p+N);//用贪心先排序
    scanf("%d-%d-%d-%d:%d",&start.year,&start.month,&start.day,&start.hour,&start.minute);//正确的输入时间
    scanf("%d-%d-%d-%d:%d",&finish.year,&finish.month,&finish.day,&finish.hour,&finish.minute);
    long long _start=totalDays(start.year,start.month,start.day);//开始日期距公元1年1月1日的天数。下同。
    long long _finish=totalDays(finish.year,finish.month,finish.day);
    long long minute=(_finish-_start)*1440;//一天有1440分钟
    minute+=mm(start,finish);
//    cout<<minute<<endl;
    int time_total=0;
    int result=0,temp=0;
    while(time_total<=minute&&temp<N)
    {
        result++;
        time_total+=p[temp];
        temp++;
        if(time_total>minute)
        {
            result--;
        }
    }//贪心选数
    cout<<result;
//    fclose(stdin);
    return 0;
}

(注意用sort函数要包含头文件algorithm)



原文地址:https://www.cnblogs.com/jiangyuechen/p/12416591.html