codeup部分-日期处理-问题 B: Day of Week

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

初做codeup题目没有成功的,现在回过来看一看,这一次记录一下比较繁琐的日期处理。


一、题目描述

问题 B: Day of Week

[命题人 : 外部导入]

时间限制 : 1.000 sec  内存限制 : 32 MB
 

题目描述

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.

样例输入 Copy

21 December 2012
5 January 2013

样例输出 Copy

Friday
Saturday

链接:Codeup新家

二、做题思路

               我认为日期处理计算出时期间隔是关键,然而时期间隔求解很繁琐,既要考虑遍历过程中是否是闰年,即考虑天数计算是计算这一年,还是下一年(根据是否是1.2月来划分),还要考虑月份,具体第几天的大小关系,一不小心就做错了。

                这一次回过头来看这个题,(题意是:输入年月日,输出星期数),非常迫切的想降低一下思维量,比较工整的求解,避免陷入在边界细节上而难受。先看一下《算法笔记》的计算时期间隔大致思路:从较靠前的时期先一年一年的跳至目标日期的前一年,然后再模拟一天一天相加,直到目标日期为止。我觉得这个就很标准,很好用,但是这一次的B_题,没给基准日期与对应星期数,我们可以使用已知的某一个日期与对应星期数做基准(比如测试用例),也因此我们读入的日期完全既有可能在基准日期的前面,也有可能在后面。

                第一次按照《算法笔记》的思路没写出来,就是在基准时期前、后的间隔天数分别是负、正,然后对7取余,对应输出即可,然后第一次直接写崩了(踩鸟的悲伤)。这一次我的思路是:不再限制年跳转到前一年就停下来,接受跳转到同一年导致月、日超出目标的情况,那怎样不乱套呢?我先设置一个基准正负符号basex为 -1。尝试交换两个日期(年月日),如果小日期在后、大日期在前了,则交换成功,我就把当前的basex变号,再去累计天数;如果大日期在后、小日期在前,交换失败,那就说明按照原来的日期移动方向没有问题,basex就保持,再去累计天数。再拓展一下,月份和日期也可以这样用。举个例子:

        读入2014/10/15 , 计算与2012/12/21天数差,

        可以发现,每次交换完后都将小日期换到了左边(比较符合人的思维),变号,按照basex去加减这一次跳转的变化天数。  这样就把间隔天数算出来了,一点点好处是不用停在前一年一天一天的模拟,而是用三次跳转到目标年月日,另外就是写起来很有层次感,缺点是也稍稍需要思考一下什么时候变号,什么时候不变。

        最后得到间隔天数后就按照这个天数计算星期数就可以了。

三、C++代码

#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<cmath>
using namespace std;

bool isRun(int year){
	return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
}
//前一时期在后一时期之前就返回true,否则交换,返回false 
bool swap_time(int &d1, int &m1, int &y1, int &d2, int &m2, int &y2){
	if(y1 < y2)
		return false;
	else if(y1 == y2 && m1 < m2)
		return false;
	else if(y1 == y2 && m1 == m2 && d1 <= d2)
		return false;
	int temp = d1; d1 = d2; d2 = temp;
	    temp = m1; m1 = m2; m2 = temp;
	    temp = y1; y1 = y2; y2 = temp;
	return true;
}

int month_day[2][13] = {{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} , {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};

int main(){
	int day, year;
	string m;
	while(cin >> day >> m >> year){
		int month = 0;
        if(m == "January") month = 1;
        else if(m == "February") month = 2;
        else if(m == "March") month = 3;
        else if(m == "April") month = 4;
        else if(m == "May") month = 5;
        else if(m == "June") month = 6;
        else if(m == "July") month = 7;
        else if(m == "August") month = 8;
        else if(m == "September") month = 9;
        else if(m == "October") month = 10;
        else if(m == "November") month = 11;
        else if(m == "December") month = 12;
		
		//初始状态 
		int day1 = 21, month1 = 12, year1 = 2012;
		int basex = -1;
		int daynum = 0;
		
		//第一阶段
		if(swap_time(day, month, year, day1, month1, year1))//以2012/12/21 星期五为基准,day,month,year保持为较小时间
			basex *= -1; 
		//先把年份加到同一年 
		if(year < year1){
			if(month <= 2)
				while(year != year1){
					isRun(year++) ? daynum += 366 : daynum += 365;
				}
			else
				while(year != year1){
					isRun(++year) ? daynum += 366 : daynum += 365;
				}
		}
		daynum = basex * daynum;
		
		//第二阶段 
		//现在年份相同,但月份可能超了,再交换试试
		if(swap_time(day, month, year, day1, month1, year1))
			basex *= -1;
		int k = 0;
		if(isRun(year)) k = 1;
		while(month != month1){
			daynum += basex * month_day[k][month];
			month++;
		}
		
		//第三阶段
		//现在月份也相同了,但天数可能超了,再交换试试
		if(swap_time(day, month, year, day1, month1, year1))
			basex *= -1;
		while(day != day1){
			daynum += basex * 1;
			day++;
		}
		
		int dis = 0;
		if(daynum < 0){//基准时间更靠后 
			dis = abs(daynum) % 7;
			switch(dis){
	            case 5: printf("Sunday\n"); break;
	            case 4: printf("Monday\n"); break;
	            case 3: printf("Tuesday\n"); break;
	            case 2: printf("Wednesday\n"); break;
	            case 1: printf("Thursday\n"); break;
	            case 0: printf("Friday\n"); break;
	            case 6: printf("Saturday\n"); break;
	        }	
		}
		else{
			dis = daynum % 7;
			switch(dis){
	            case 2: printf("Sunday\n"); break;
	            case 3: printf("Monday\n"); break;
	            case 4: printf("Tuesday\n"); break;
	            case 5: printf("Wednesday\n"); break;
	            case 6: printf("Thursday\n"); break;
	            case 0: printf("Friday\n"); break;
	            case 1: printf("Saturday\n"); break;
	        }	
    	}
	}
	return 0;
}

总结

就是这么多了,祝你每一天都开心。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值