问题 E: 趣味程序设计_打印日历(超详细解题思路)

题目描述打印出任意年份的日历。提示:要判断该年份是否是闰年,若是闰年,二月为29天,平年为28天。而判断闰年的规则是:如果((该年能被4除尽且不能被100除尽) 或 能被400除尽),则该年是闰年。输入输入年份。输出与输入相对应,输出该年12个月的日历。

提示
重点是要将某天对应星期几算出来,其它就只要搞好排版就行了。关于求星期几,可以先找一个基准,比如1年1月1日是星期一,或1990年1月1日是星期一,然后按7天一个周期,计算出任意一天是星期几。当然,这还需要知道每个月有多少天,2月份还要看是否是闰年。

本题表面代码较长实际上只要明白思路就可以很快写出来。
本题要注意分成几个问题模块来解决。(很多题目都是要具有分治法的思想)
1、正如提示中所写到的,首先关键是找到指定年的1月1号是星期几。
2、如何按照指定的格式来打印日历。
一、
对于第一个问题,我们选定特殊的年份(1990)作为基准,我们发现对于制定年份year我们可以求出其1月1号与1990年1月1号的距离天数。然后我们想=像下面填各自一样把这些天没=每7个一行的填,这样就可以计算出来该年的1月1号是星期几
在这里插入图片描述
就像上面这样是可以计算1990—year年共N(不算1月1号)天,我们所得余数+1就是该年1月1号是星期几。(同理我们也可以判断year<1990年的星期几是怎么来算,代码后面会再次进行解答,请举一反三多多思考,看看有没有弄懂)
另外解释一下我们的N不算1月1号的好处。
1、方便我们理解来计算,更适合填格法的理解。
2、当我们使用N%7==0时,实际上是到了周日,如果算上要另外考虑各种情况。
但是使用+1,当遇到周日时得0,+1刚好是周一。如果遇到周六+1刚好是7不用被算为0;

二、我们来看怎么按照要求来输出。
1、我们使用二维数组f[i][j]来表示,这样标志了两个信息:月份和每月的日期.我们每次月份可以j++的时候我们就打印一个星期表格:
*Mon Tue Wed Thu Fri Sat Sun
2、如何让日期编号和星期对齐:一个极为重要的规律;这些星期的英文都是3格;将一整段分割发现,每个星期几均占4格:使用%4d
3、如何使得没到周日时自动转行,我们可以使用一个计步器count++来累计步数(注意,count不是从0开始,而是从每月1号对应的周几开始)

三、可以自发思考,也可以学习下面代码。
主要是理清函数设计中如何把各个模块有机结合起来。

下面是代码:

#include<stdio.h>
int fun(int year)//通过判断输入年份闰平来返回的总天数;
{
    if((year%4==0&&year%100!=0)||(year%400==0))
        return 366;
    else return 365;
}
int main()
{
    int i;
    int year;
    scanf("%d",&year);
    if(year>=1990)//包括1990
    {
        /**下面为计算从1990到year总天数**/
        int sum=0;//计算总天数;
        for(i=1990;i<year;i++)//即不要算上year;
        {
            sum=sum+fun(i);//fun判断该年的总日期
        }
        /**-----------------------------**/
        int ri=sum%7+1;//找出该年的1月1号是星期几
        /**按照要求进行输出打印日历**/
        int f[2][12]={{31,28,31,30,31,30,31,31,30,31,30,31},{31,29,31,30,31,30,31,31,30,31,30,31}};
        int a;
        if(fun(year)==365)a=0;//判断平闰年不需要再写函数
        else a=1;//避免重复代码
            int j=1,k;
            int count=ri;//用来计算每次到达星期日时转行;同时“用来定位每月的1号在哪个位置”(可以直接使用ri;)
            for(j=0;j<12;j++)//输出每月的打印
            {
                 printf("*Mon Tue Wed Thu Fri Sat Sun\n");
                /**输入1月1号的位置//之后是输入每月的1号(都需要定位)**/
                for(k=1;k<=(count-1)*4+3;k++)
                printf(" ");
                printf("1");
                /**-------------**/
                /**打印其他的日期**/
                for(k=2;k<=f[a][j];k++)
                {
                    if(count==7)
                    {printf("\n");count=0;}
                    count++;
                    printf("%4d",k);
                }
                count%=7;count++;//定位每月1号位置
                printf("\n");
            }

     }

     else
    {
        /**下面为计算从year到1990总天数**/
        int sum=0;//计算总天数;
        for(i=year;i<1990;i++)//即不要算上1990;
        {
            sum=sum+fun(i);//fun判断该年的总日期
        }
        /**-----------------------------**/
        int ri=8-sum%7;//找出该年的1月1号是星期几
        if(sum%7==0)
            ri=1;
        /**按照要求进行输出打印日历**/
        int f[2][12]={{31,28,31,30,31,30,31,31,30,31,30,31},{31,29,31,30,31,30,31,31,30,31,30,31}};
        int a;
        if(fun(year)==365)a=0;//判断平闰年不需要再写函数
        else a=1;//避免重复代码
            int j=1,k;
            int count=ri;//用来计算每次到达星期日时转行;同时“用来定位每月的1号在哪个位置”(可以直接使用ri;)
            for(j=0;j<12;j++)//输出每月的打印
            {
                 printf("*Mon Tue Wed Thu Fri Sat Sun\n");
                /**输入1月1号的位置//之后是输入每月的1号(都需要定位)**/
                for(k=1;k<=(count-1)*4+3;k++)
                printf(" ");
                printf("1");
                /**-------------**/
                /**打印其他的日期**/
                for(k=2;k<=f[a][j];k++)
                {
                    if(count==7)
                    {printf("\n");count=0;}
                    count++;
                    printf("%4d",k);
                }
                count%=7;count++;//定位每月1号位置
                printf("\n");
            }

     }
    return 0;
}

下面是其小于1990时的计算该年1月1号的方法:
在这里插入图片描述
创作不易,点个赞再走呗

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值