HDU 6112 今夕何夕【2017"百度之星"】【日期模擬計算】【基姆拉爾森計算公式】【蔡勒公式】
阿新 • • 發佈:2019-02-12
今夕何夕
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1668 Accepted Submission(s): 594
Problem Description 今天是2017年8月6日,農曆閏六月十五。
小度獨自憑欄,望著一輪圓月,發出了“今夕何夕,見此良人”的寂寞感慨。
為了排遣鬱結,它決定思考一個數學問題:接下來最近的哪一年裡的同一個日子,和今天的星期數一樣?比如今天是8月6日,星期日。下一個也是星期日的8月6日發生在2023年。
小貼士:在公曆中,能被4整除但不能被100整除,或能被400整除的年份即為閏年。
Input 第一行為T,表示輸入資料組數。
每組資料包含一個日期,格式為YYYY-MM-DD。
1 ≤ T ≤ 10000
YYYY ≥ 2017
日期一定是個合法的日期
Output 對每組資料輸出答案年份,題目保證答案不會超過四位數。
Sample Input 3 2017-08-06 2017-08-07 2018-01-01
Sample Output 2023 2023 2024
Source
題意簡單,但是日期類題目計算有點麻煩。。。。
1.直接模擬。
題目中說‘今天’是2017年8月6日,星期日,我們要尋找下一個8月6日也是星期日的年份。
這裡要分三種情況進行討論。
1.1 若開始日期在在3月以後(包含3月,無論今年是平年還是閏年),則到下一年今天則會經過365天,星期數會向後推一天(365%7=1)
1.2 若開始日期在2月29日,則到下一個2月29日至少要過4年。
1.3 如開始日期在2月29日之前:
1.3.1 若今年為閏年,則到明年今日要經過366天,否則為365天。
AC程式碼1.
模擬:
/** * 行有餘力,則來刷題! * 部落格連結:http://blog.csdn.net/hurmishine * 個人部落格網站:http://wuyunfeng.cn/ */ #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn=1e1+5; int a[maxn]; int getDay(int y)//年份天數 { /** 364/7=52 */ if(y%400==0||y%100!=0&&y%4==0) return 2; return 1; } int main() { //freopen("C:\\Users\\hncu_acm\\Desktop\\data.txt","r",stdin); int T; cin>>T; while(T--) { int y,m,d; scanf("%d-%d-%d",&y,&m,&d); int sum=0; if(m>2) { do { y++; sum+=getDay(y); sum%=7; } while(sum); } else { if(m==2&&d==29) { do { y++; sum+=getDay(y); sum%=7; if(sum==0&&getDay(y)==2) break; } while(true); } else { do { sum+=getDay(y); y++; sum%=7; } while(sum); } } cout<<y<<endl; } return 0; }
AC程式碼2:
基姆拉爾森計算公式:
W= (d+2*m+3*(m+1)/5+y+y/4-y/100+y/400) mod 7
在公式中d表示日期中的日數,m表示月份數,y表示年數。注意:在公式中有個與其他公式不同的地方:
把一月和二月看成是上一年的十三月和十四月,例:如果是2004-1-10則換算成:2003-13-10來代入公式計算。
#include <iostream> #include <stdio.h> #include <string.h> #include <vector> #include <algorithm> #include <math.h> #include <queue> #define LL long long using namespace std; int year,month,day; bool isLeap(int x) { if((x%4==0&&x%100!=0)||x%400==0) return true; return false; } int cal(int y,int m,int d) { if(m<3) { m+=12; --y; } int W=(d+1+2*m+3*(m+1)/5+y+(y>>2)-y/100+y/400)%7; return W==0?7:W; } bool judge(int x) { //起始年是閏年,但是今年不是 if(isLeap(year)&&!isLeap(x)&&(month==2&&day==29)) { return true; } return false; } int main() { int t; scanf("%d",&t); while(t--) { scanf("%d-%d-%d",&year,&month,&day); int pos=cal(year,month,day); int kk; for(int i=year+1;; ++i) { kk=cal(i,month,day); if(judge(i)) continue; if(kk==pos) { printf("%d\n",i); break; } } } return 0; }
AC程式碼3,
蔡勒公式
以1582年10月4日為例:
1582年10月4日後:w = (d + 1+ 2*m+3*(m+1)/5+y+y/4-y/100+y/400)%7;
1582年10月4日前:w = (d+1+2*m+3*(m+1)/5+y+y/4+5) % 7;
w:星期; w對7取模得:0-星期日,1-星期一,2-星期二,3-星期三,4-星期四,5-星期五,6-星期六
c:世紀(年份前兩位數)
y:年(後兩位數)
m:月(m大於等於3,小於等於14,即在蔡勒公式中,某年的1、2月要看作上一年的13、14月來計算,比如2003年1月1日要看作2002年的13月1日來計算)
d:日
AC程式碼:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <iostream>
using namespace std;
int is_run(int year)
{
if(year%400==0||(year%4==0&&year%100!=0))
return 1;
return 0;
}
int Zeller(int year,int month,int day)///蔡勒公式算星期
{
if (month==1||month==2)
{
year--;
month+=12;
}
int c=year/100;
int y=year-c*100;
int week=(c/4)-2*c+(y+y/4)+(13*(month+1)/5)+day-1;
while(week<0){week+=7;}
week%=7;
return week;
}
int main()
{
int year,month,day,T;
scanf("%d",&T);
while (T--)
{
scanf("%d-%d-%d",&year,&month,&day);
int week=Zeller(year,month,day);
int week2;
if (month==2&&day==29)///如果輸入為閏年的2月29號
{
for (int i=year+4;i<=9999;i+=4)///每四年列舉
{
if (!is_run(i)) continue;///不是閏年就PASS
week2=Zeller(i,month,day);
if (week==week2)
{
printf("%d\n",i);
break;
}
}
}
else
{
for (int i=year+1;i<=9999;i++)
{
week2=Zeller(i,month,day);
if (week==week2)
{
printf("%d\n",i);
break;
}
}
}
}
return 0;
}
參考部落格:http://blog.csdn.net/clx55555/article/details/77154461
測試資料:
10
2017-08-06
2018-08-07
2019-08-06
2020-08-07
2021-08-06
2017-01-07
2018-01-01
2019-01-07
2020-01-01
2020-02-29
2023
2029
2024
2026
2027
2023
2024
2030
2025
2048