九度OJ 1043 Day of Week

原题地址:http://ac.jobdu.com/problem.php?pid=1043 题目描述:

We now use the Gregorian style of dating in Russia. The leap years are years with number divisible by 4 but not divisible by 100, or divisible by 400.
For example, years 2004, 2180 and 2400 are leap. Years 2004, 2181 and 2300 are not leap.
Your task is to write a program which will compute the day of week corresponding to a given date in the nearest past or in the future using today’s agreement about dating.

输入:

There is one single line contains the day number d, month name M and year number y(1000≤y≤3000). The month name is the corresponding English name starting from the capital letter.

输出:

Output a single line with the English name of the day of week corresponding to the date, starting from the capital letter. All other letters must be in lower case.

样例输入:
9 October 2001
14 October 2001
样例输出:
Tuesday
Sunday
提示:

Month and Week name in Input/Output:
January, February, March, April, May, June, July, August, September, October, November, December
Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday

来源:
2008年上海交通大学计算机研究生机试真题
本题的思路与前一篇【九度OJ 1096 日期差值http://blog.csdn.net/lecholin/article/details/65450591】基本一致。

值得注意的有以下几点:

  1. 之前的题目求的是两日期差值,这次只给出了一个需要求解的日期,怎么知道星期几呢?只需要设定另外一个日期为今天(比如做题时是2017年3月10日,星期五),两个日期做差值,加上今天的星期数,再取周期为7模即可。
  2. 如果给定的日期小于当下的日期(大多数测试应该也都是这样的),那就会出现这样的情况:差值为负,不能简单处理为转绝对值再%7(比如今天是周一,遇到-2%7时,用2%7来相加的意义显然不同),因此涉及到负数取模的问题,在C语言中,a % b = a - (a / b) * b,C99 规定余数和被除数的符号相同,为了把负数取模的负值映射回b所在的正数区间,采用先模b再加b的结果再模b,比如本题中的(result = (interv%7+7)%7)。假设今天是7月16日周一,要求7月8日是星期几(日),-8%7=-1+7=6%7=6,即-8=(-2)*7+6,所以是今天的1(一)+6(差值的正数映射)=7(日)。关于负数取模运算,还有需要学习的地方。
  3. 九度OJ坑爹的C98不支持map全局变量的初始化赋值,只能每次insert一个pair对....以后还是要先熟悉上机环境啊
AC代码如下:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <map>
#include <string>
#define IsLeapYear(x) ((x%4 == 0 && x%100 != 0)||x%400 == 0)?1:0
#define MAX_YEAR 3001
using namespace std;

int dayOfMonth[13][2] //每个月在平闰年的最大天数
{
    0,0,
    31,31,
    28,29, //二月的平闰情况
    31,31,
    30,30,
    31,31,
    30,30,
    31,31,
    31,31,
    30,30,
    31,31,
    30,30,
    31,31
};

struct DATE
{
    int Year, Month, Day;
    void next_day()
    {
        ++Day;
        if (Day > dayOfMonth[Month][IsLeapYear(Year)])
        {
            Day = 1;
            ++Month;
            if (Month > 12)
            {
                Month = 1;
                ++Year;
            }
        }
    }
};

map<string, int> monthToInt; //月份到数字的转换
string week[7]={"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};

int offset[MAX_YEAR][13][32];
void PreProcess() //预处理
{
    DATE tmp;
    tmp.Year=0; tmp.Month=1; tmp.Day=1;
    int interval = 0;
    while(tmp.Year != MAX_YEAR)
    {
        offset[tmp.Year][tmp.Month][tmp.Day] = interval;
        ++interval;
        tmp.next_day();
    }
}

void shitC98()
{
    monthToInt.insert(pair<string,int>("January",1));
    monthToInt.insert(pair<string,int>("February",2));
    monthToInt.insert(pair<string,int>("March",3));
    monthToInt.insert(pair<string,int>("April",4));
    monthToInt.insert(pair<string,int>("May",5));
    monthToInt.insert(pair<string,int>("June",6));
    monthToInt.insert(pair<string,int>("July",7));
    monthToInt.insert(pair<string,int>("August",8));
    monthToInt.insert(pair<string,int>("September",9));
    monthToInt.insert(pair<string,int>("October",10));
    monthToInt.insert(pair<string,int>("November",11));
    monthToInt.insert(pair<string,int>("December",12));
}

int main()
{
    PreProcess();
    shitC98();
    int day, year;
    string month;
    int interv, result;
    int today = offset[2017][3][10];
    //做题时是2017年3月10日,星期5
    while(cin >> day >> month >> year)
    {
        interv = offset[year][monthToInt[month]][day] - today + 5;
        result = (interv%7+7)%7;
        //将计算后的下标用7对其取模,再+7保证非负数
        cout << week[result] << endl;
    }
    return 0;
}

内存占用:6404Kb,耗时:10ms
算法复杂度:O(n),其中map底层是用红黑树实现的,查找时间复杂度是log(n)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值