1. 程式人生 > >HDU 6112 今夕何夕【2017"百度之星"】【日期模擬計算】【基姆拉爾森計算公式】【蔡勒公式】

HDU 6112 今夕何夕【2017"百度之星"】【日期模擬計算】【基姆拉爾森計算公式】【蔡勒公式】

今夕何夕

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