[蓝桥杯][算法训练VIP]黑色星期五(基姆拉尔森计算公式)

黑色星期五

题目描述

有些西方人比较迷信,如果某个月的13号正好是星期五,他们就会觉得不太吉利,用古人的说法,就是“诸事不宜”。请你编写一个程序,统计出在某个特定的年份中,出现了多少次既是13号又是星期五的情形,以帮助你的迷信朋友解决难题。

说明:(1)一年有365天,闰年有366天,所谓闰年,即能被4整除且不能被100整除的年份,或是既能被100整除也能被400整除的年份;(2)已知1998年1月1日是星期四,用户输入的年份肯定大于或等于1998年。

输入

输入只有一行,即某个特定的年份(大于或等于1998年)。

输出

输出只有一行,即在这一年中,出现了多少次既是13号又是星期五的情形

样例输入

1998

样例输出

3

分析

方法一 :暴力法

第一种方法是用正常的思路,判断这一年每月13号是否为星期五,那么怎么才能判断这一天是星期五呢,我们知道,1月1日是星期四,那么1月2日就是星期五,以后每隔七天又是星期五。因此如果天数对7求余等于2,那么这一天就是星期五。

那么又有一个问题了?我们怎样求天数。比如,2020年2月13日距1998年1月1日有多少天,只要求出天数,这个问题就解决了。我们可以直接暴力解决,用for循环将每一年的天数相加,注意不要加上你所求的这一年,因为我们就是要统计这一年黑色星期五的次数。

#include<stdio.h>
int main (void){
 int year;
 scanf("%d",&year);
 int i,j;
 int tab[2][13]={
  {0,31,28,31,30,31,30,31,31,30,31,30,31},//非闰年
  {0,31,29,31,30,31,30,31,31,30,31,30,31},//闰年
 };
 int day=0,flag;
 for(i=1998;i<year;i++){
  flag=((i%4==0&&i%100!=0) || (i%400==0));//判断闰年
  if(flag){
   day+=366;
  }
  else{//计算所求年之前所有的天数
   day+=365;
  }
 }
 flag=((year%4==0&&year%100!=0) || (i%400==0));//判断所求这一年是否为闰年
 int count=0;
 for(i=1;i<13;i++){
  day+=tab[flag][i-1];//加上上一月的天数
  if((day+13)%7==2){//判断是否为黑色星期五
   count++;
  }
 }
 printf("%d",count);
 return 0;
}

方法二 :基姆拉尔森计算公式

week=(d+2m+3(m+1)/5+y+y/4-y/100+y/400+1)%7;

可以直接计算一个日期是星期几,这样就方便多了。

在公式中d表示日期中的日数,m表示月份数,y表示年数。
注意:在公式中有个与其他公式不同的地方:
把一月和二月看成是上一年的十三月和十四月,例:如果是2004-1-10则换算成:2003-13-10来代入公式计算。

此公式的推导此处不详细解释,读者如感兴趣,可自行百度。

百度百科中关于基姆拉尔森计算公式的介绍

知道了这个公式后,此题是不是变得更简单了呢?话不多说,代码如下。

参考代码

#include<stdio.h>
int main (void){
 int d=13,m,y,year;
 scanf("%d",&year);
 int i,count=0,week;
 for(i=1;i<=12;i++){
    y=year;
    m=i;
    if(m==1||m==2){//一月二月时月份与年份都会发生变化
      m+=12;//因此定义两个新变量y,m
      y--;
    }
    week=(d+2*m+3*(m+1)/5+y+y/4-y/100+y/400+1)%7;
    if(week==5){
      count++;
    }
 }
 printf("%d",count);
 return 0;
}

如有错误之处,敬请指正!!!

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值