日期的具体公式计算

蔡勒公式

蔡勒(Zeller)公式,是一个计算星期的公式,随便给一个日期,就能用这个公式推算出是星期几。

符号意义

w:星期; w对7取模得:0-星期日,1-星期一,2-星期二,3-星期三,4-星期四,5-星期五,6-星期六
c:世纪(注:一般情况下,在公式中取值为已经过的世纪数,也就是年份除以一百的结果,而非正在进行的世纪,也就是现在常用的年份除以一百加一;不过如果年份是公元前的年份且非整百数的话,c应该等于所在世纪的编号,如公元前253年,是公元前3世纪,c就等于-3)
y:年(一般情况下是后两位数,如果是公元前的年份且非整百数,y应该等于cMOD100+100)
m:月(m大于等于3,小于等于14,即在蔡勒公式中,某年的1、2月要看作上一年的13、14月来计算,比如2003年1月1日要看作2002年的13月1日来计算)
d:日
[ ]代表取整,即只要整数部分。

举例

下面以中华人民共和国成立100周年纪念日那天(2049年10月1日)来计算是星期几,过程如下:
w=y+[y/4]+[c/4]-2c+[26(m+1)/10]+d-1
=49+[49/4]+[20/4]-2×20+[26×(10+1)/10]+1-1
=49+[12.25]+5-40+[28.6]
=49+12+5-40+28
=54 (除以7余5)
即2049年10月1日(100周年国庆)是星期五。
再比如计算2006年4月4日,过程如下:
w=y+[y/4]+[c/4]-2c+[26(m+1)/10]+d-1
=6+[6/4]+[20/4]-220+[26(4+1)/10]+4-1
=-12 (除以7余5,注意对负数的取模运算!实际上应该是星期二而不是星期五)
w=(-12%7+7)%7=2;

代码实现

#include<stdio.h>
int main()
{
 int year, month, day;
 while (scanf("%d %d %d", &year, &month, &day) != EOF)
 {
  if (month == 1 || month == 2)//判断month是否为1或2 
   year--, month += 12;
  int c = year / 100;
  int y = year - c * 100;
  int week = y + y / 4 + c / 4 - 2 * c + 26 * (month + 1) / 10 + day - 1;
  while (week < 0)
   week += 7;
  week %= 7;
  switch (week)
  {
  case 1:printf("Monday\n"); break;
  case 2:printf("Tuesday\n"); break;
  case 3:printf("Wednesday\n"); break;
  case 4:printf("Thursday\n"); break;
  case 5:printf("Friday\n"); break;
  case 6:printf("Saturday\n"); break;
  case 0:printf("Sunday\n"); break;
  }
 }
 return 0;
}

1基姆拉尔森计算公式

Week=(Day + 2Month + 3(Month+1)/5 + Year + Year/4 - Year/100 + Year/400) % 7
(其中的Year是4位数的,如2009。“%”号是等式除7取余数)
注意:
i. 该公式中要把1月和2月分别当成上一年的13月和14月处理。
例如:2008年1月4日要换成 2007年13月4日带入公式。
ii.该式对应的与蔡勒公式有点区别:“0”为星期1,……,“6”为星期日。
改进:
该式可能与蔡勒公式的计算都是较为复杂,但有改进的地方:对于世纪这个概念不被引用,直接就是计算年代数(4位数)的!既不用再把 世纪 和 年代数(后两位)分开。

代码实现

#include <iostream>
using namespace std;
int CaculateWeekDay(int y,int m,int d)
{
if(m==1) m=13,y--;
if(m==2) m=14,y--;
int week=(d+2*m+3*(m+1)/5+y+y/4-y/100+y/400)%7;
return week;
}
int main()
{
    int y,m,d;
    for(;;){
    cin>>y>>m>>d;
    int week=CaculateWeekDay(y,m,d);
    switch(week)
    {
    case 0: cout<<"Monday星期一"<<endl; break;
    case 1: cout<<"Tuesday星期二"<<endl; break;
    case 2: cout<<"Wednesday星期三"<<endl; break;
    case 3: cout<<"Thursday星期四"<<endl; break;
    case 4: cout<<"Friday星期五"<<endl; break;
    case 5: cout<<"Saturday星期六"<<endl; break;
    case 6: cout<<"Sunday星期日"<<endl; break;
    }
    }
    return 0;
}

实际应用

D - The Lucky Week ZOJ - 3939

Edward, the headmaster of the Marjar University, is very busy every day and always forgets the date.

There was one day Edward suddenly found that if Monday was the 1st, 11th or 21st day of that month, he could remember the date clearly in that week. Therefore, he called such week “The Lucky Week”.

But now Edward only remembers the date of his first Lucky Week because of the age-related memory loss, and he wants to know the date of the N-th Lucky Week. Can you help him?

Input
There are multiple test cases. The first line of input is an integer T indicating the number of test cases. For each test case:

The only line contains four integers Y, M, D and N (1 ≤ N ≤ 109) indicating the date (Y: year, M: month, D: day) of the Monday of the first Lucky Week and the Edward’s query N.

The Monday of the first Lucky Week is between 1st Jan, 1753 and 31st Dec, 9999 (inclusive).

Output
For each case, print the date of the Monday of the N-th Lucky Week.

Sample Input
2
2016 4 11 2
2016 1 11 10
Sample Output
2016 7 11
2017 9 11

找循环结(可以为400)

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<queue>
#include<map>
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
using namespace std;
int x[5]={1,11,21};
int whatday(int d,int m,int y){
    int ans;
    if(m==1||m==2){
        m+=12,y--;
    }
    if((y<1752)||(y==1752&&m<9)||(y==1752&&m==9&&d<3))
        ans=(d+2*m+3*(m+1)/5+y+y/4+5)%7;
    else
        ans=(d+2*m+3*(m+1)/5+y+y/4-y/100+y/400)%7;
    return ans;
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        int a,b,c,n;scanf("%d%d%d%d",&a,&b,&c,&n);n--;
        int ans=0,flag=0,sum1=0;int h=c,h1=0;
        for(int i=b;i<=12;i++){
                if(h1==0){h=c/10;h1=1;}
                else h=-1;
            for(int j=h+1;j<3;j++){
                if(ans==n){flag=1;break;}
                if(whatday(x[j],i,a)==0){ans++;sum1++;b=i;c=x[j];}
            }
            if(flag==1)break;
        }
        if(flag==1){cout<<a<<" "<<b<<" "<<c<<endl;continue;}
        a+=1;int sum2=0;flag=0;int A,B,C;
        for(int i=a;i<a+400;i++){
            for(int j=1;j<=12;j++){
                for(int k=0;k<3;k++){
                    if(ans==n){flag=1;break;}
                    if(whatday(x[k],j,i)==0)
                       {ans++;sum2++;
                       A=i;B=j,C=x[k];}
                }
                if(flag==1)break;
            }
            if(flag==1)break;
        }
        if(flag==1){cout<<A<<" "<<B<<" "<<C<<endl;continue;}
        int src=(n-sum1)/sum2;
        int y=n-sum1-src*sum2,t=a+(src*400);
        if(y==0){
            for(int i=1;i<=12;i++){
                for(int j=0;j<3;j++){
                    if(whatday(x[j],i,y)==0){a=t;b=i;c=x[j];}
                }
            }
            cout<<a<<" "<<b<<" "<<c<<endl;continue;
        }
        int xx=0,flag1=0;
        for(int i=t;xx<y;i++){
            for(int j=1;j<=12&&xx<y;j++){
                for(int k=0;k<3&&xx<y;k++){if(xx==y){flag1=1;break;}
                   if(whatday(x[k],j,i)==0){xx++;a=i;b=j;c=x[k];}
                }if(flag1==1)break;
            }if(flag1==1)break;
        }
        cout<<a<<" "<<b<<" "<<c<<endl;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值