#历法相关:月历

#以此类推,也许该出现年历了。

…或者周历?

历法
来分析一下题目想让我们干什么吧:
提供年与月,输出月历,输出格式如上。
第一行是固定的,哪个月都是这样,所以无论如何就可以在打印的那个函数里第一行就写上这个:

printf("     SUN     MON     TUE     WED     THU     FRI     SAT\n");

然后是找那个月份开始的日期以及打印天数,两个问题。
要打印的天数好说,一年到头12个月份的天数基本上没变过,在2月判断一下就好。

所以嗦这道题的问题其实就是,找开始的那一天。
那么怎么找呢?不用担心,题目给的两个数据还没开始用。
通过 年与月 来找出 目标月份的第一周 从星期几开始,对吧?

那就要判断,从某一个确定的基准日期以后,一直到目标日期,过了多少天,把天数模个7就是多出来的部分了。其中还有些可以优化的部分,先不谈,这个就先可以。

bool leap(int year){
	return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0);
}
void print(int year,int month){

	int y = year % 400; // 优化一下,400年一轮回,历法星期啥的一样的
	int sumday = 0;
	
	for (int i = 1;i < y;i++){ //公元一年一月一日开始,星期一。(比2000为基准舒服
		if (leap(i))sumday = sumday + 366;
		else sumday = sumday + 365;
	}
	//记 过了那么多年总共过的天数,最后再加上 目标月份那年 前面月份 的天数,最后%7
	//其实可以边加边%7
	
	int mon[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
	if (leap(year)) mon[1] = 29;
	for (int i = 0;i < month-1;i++){ //eg.求8月,累加1~7月的天数,0~6号数组位置
		sumday = sumday + mon[i];
	}
	sumday = sumday % 7;
	int blank = (sumday + 1) % 7; //公元1/1/1是星期一,月历的空格位保底有一个
	//打印的空格数
	for (int i = 1;i <= blank;i++){
		printf("        ");
	}
	for (int i = 1;i <= mon[month-1];i++){
		printf("%8d",i);
		if ((i + blank) % 7 == 0) printf("\n");
	}
}

补上一个main,完满了

int main(){
    int y,m;
    scanf("%d%d",&y,&m);
    print(y,m);
    return 0;
}

啊没什么麻烦的。那我们来试试那个吉姆拉尔森公式?
“通过年月日来判断那一天是星期几”

参考:吉姆拉尔森公式计算公式
这里修改一下,丢进来用,效果如下:

bool leap(int year){
    return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0);
}

int jier(int day,int month,int year){
    if (month==1||month==2){
        month+=12;
        year--;
    }
    int week = (day + 2*month + 3 * (month+1)/5 + year + year/4 - year/100 + year/400 + 1) % 7;
    return week;
}

void print(int year,int month){
    
    printf("     SUN     MON     TUE     WED     THU     FRI     SAT\n");
    
    int d = jier(1,month,year);
    
    for (int i = 1;i <= d;i++){
        printf("        ");
    }
    
    int mon[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
    if (leap(year)) mon[1] = 29;
    
    for (int i = 1;i <= mon[month-1];i++){
        printf("%8d",i);
        if ((i + d) % 7 == 0) printf("\n");
    }
}

如果能记住公式,那代码逻辑又可以化简一丢丢了。可惜公式好长…
不过原来的思路经过轮回模法只需要加和最多四百次,数据量也不大,记不住公式可以用那个。
公式有个规律:(日 + 2 * 月 + 3 *(月 + 1)/ 5 + 年 + 年 / 4 - 年 / 100 + 年 / 400 + 1)% 7
关于年的部分与闰年的几个参数定义有关。
公式中的参数是用来调误差的。

…好像也不是很难记?

看这月历,一月份了,
可注意别感冒了嗷。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值