算法提高 日期计算 蓝桥杯 详解

算法提高 日期计算  
时间限制:1.0s   内存限制:256.0MB
    
问题描述
  已知2011年11月11日是星期五,问YYYY年MM月DD日是星期几?注意考虑闰年的情况。尤其是逢百年不闰,逢400年闰的情况。
输入格式
  输入只有一行
  YYYY MM DD
输出格式
  输出只有一行
  W
数据规模和约定
  1599 <= YYYY <= 2999
  1 <= MM <= 12
  1 <= DD <= 31,且确保测试样例中YYYY年MM月DD日是一个合理日期
  1 <= W <= 7,分别代表周一到周日
样例输入
2011 11 11
样例输出
5

我一直对这种日期计算计算的题目存在恐惧感,因为这类题目普遍不难,但是多一天少一天的问题搞得我头都大了,好在今天仔细在纸上画了一下,想出了一种比较通用的做法,如有雷同,纯属你抄我大笑开玩笑,但我还是要好好整理一下解题思路


1.闰年问题:当然是通过函数判断闰年,我想如果不是万年一见的水题,一般计算日期时间都是要考虑闰年的。闰年的两种情况:1.能被4整除但不能被100整除;2.能被400整除,也就是常说的四年一闰,百年不闰,四百年再闰

2.天数问题:这里题目一般都会给出一个基础日期的信息,但是相信我,最好是花点时间算出某一年1月1号的信息,因为这会让思路变得很清晰,如果你算不出来,也有一个投机取巧的方法(假如条件允许),电脑下面的时间可以给你提供很全面正确的信息,有了基础天数后,以本题为例,2011年1月1日是星期6。


首先算年份差所带来的天数差


(1)给出的年份比基础年份小或者就是2011年,比如2009年,我们首先计算2009年1月1日到2011年1月1日的天数,相信这个应该难不倒你吧,闰年366天,非闰年365天,2009年开始,算完2010年结束。

(2)给出的年份比基础年份大,比如2013年,当然就是从2011年开始,算完2012年结束

经过这个步骤,得到day1


然后算由于月份和天的差所带来的天数差


(1)首先当然是计算1月1日到给定的日期(比如3月8号)的天数,计算的时候是用循环,从1月开始加,加完2月结束,最后再加上8天,但是注意,你此时算出的天数多了1,举个例子,1月1日到1月3日有几天?当然是2天,这要比3多1天,因为起始点就是1了,明白了这个,我们就可以用得出的天数减1,从而获得了第二个天数day2


关键时刻,计算真实的天数差


(1)如果给出的年份小于等于基础年份,那么我们得到的day1实际上是算多了,而且正好多出了day2天,所以真正的天数差是day1-day2

(2)如果给出的年份大于基础年份,那么天数实际上是算少了,少了day2天,所以真正的天数是day1+day2


在得出天数之后,我们还要分情况,首先将得到的天数差day%7,得到星期差

(1)如果给出的年份小于等于基础年份,那么应该从基础时间(星期六)向负方向数day%7天,注意1之后要变成7

(2)如果给出的年份大于基础年份,那么应该从基础时间(星期六)向正方向数day%7天,注意7之后要变成1


最终我们就得到了正确的星期


#include<iostream>
#include<cmath>
using namespace std;

bool leap(int year)
{
	if(year%4==0&&year%100!=0)
	return true;
	if(year%400==0)
	return true;
	return false;
} 

int getYD(int year)
{
	int sum=0;
	int i;
	if(year<=2011)
	{
		for(i=year;i<2011;i++)
		{
			if(leap(i))
			sum+=366;
			else
			sum+=365;	
		}
	}
	if(year>2011)
	{
		for(i=2011;i<year;i++)
		{
			if(leap(i))
			sum+=366;
			else
			sum+=365;
		}
	}
	return sum;
}

int getMD(int year,int mon,int day)
{
	int i;
	int sum=0;
	for(i=1;i<mon;i++)
	{
		if(i==1||i==3||i==5||i==7||i==8||i==10||i==12)
		sum+=31;
		if(i==4||i==6||i==9||i==11)
		sum+=30;
		if(i==2&&leap(year))
		sum+=29;
		if(i==2&&!leap(year))
		sum+=28;
	}
	sum=sum+day-1;
	return sum;
}



int main()
{
	int year,mon,day,sum;
	while(cin>>year>>mon>>day)
	{
		sum=getYD(year);
		//cout<<getMD(year,mon,day)<<endl;;
		if(year<2011)
		{
			sum=sum-getMD(year,mon,day);
			//cout<<sum<<endl;
			cout<<(sum%7==6?7:abs(6-(sum%7)))<<endl;
		}
		else
		{
			sum=sum+getMD(year,mon,day);
			//cout<<sum<<endl;
			cout<<((6+(sum%7))>7?((6+(sum%7))%7):(6+(sum%7)))<<endl;
		}
		
		
	}
	return 0;
}















  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值