演算法提高 日期計算 藍橋杯 詳解
YYYY MM DD 輸出格式 輸出只有一行
W 資料規模和約定 1599 <= YYYY <= 2999
1 <= MM <= 12
1 <= DD <= 31,且確保測試樣例中YYYY年MM月DD日是一個合理日期
1 <= W <= 7,分別代表週一到週日
我一直對這種日期計算計算的題目存在恐懼感,因為這類題目普遍不難,但是多一天少一天的問題搞得我頭都大了,好在今天仔細在紙上畫了一下,想出了一種比較通用的做法,如有雷同,純屬你抄我開玩笑,但我還是要好好整理一下解題思路
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;
}