灰灰考研機試班 | 基礎練習二 問題 B: 日曆本 | 入門題-模擬 | 日期、星期相關計算

問題 B: 日曆本

時間限制: 1 Sec  內存限制: 32 MB

題目描述

我們經常需要使用日曆,所以需要一個能生成日曆的程序。
先要求你寫一個程序,只需要輸入年份,就能生成正確的日曆。

輸入

輸入包含多組測試數據。每組輸入一個整數Y(1800<=Y<=2100),表示公元年份。

輸出

對於每組輸入,輸出對應的日立本。選中下面的輸出樣例查看具體的輸出格式,注意空格的輸出。

樣例輸入 Copy

2010

樣例輸出 Copy

(注:不包括行號)

                              2010                              

      January               February               March        
Su Mo Tu We Th Fr Sa  Su Mo Tu We Th Fr Sa  Su Mo Tu We Th Fr Sa
                1  2      1  2  3  4  5  6      1  2  3  4  5  6
 3  4  5  6  7  8  9   7  8  9 10 11 12 13   7  8  9 10 11 12 13
10 11 12 13 14 15 16  14 15 16 17 18 19 20  14 15 16 17 18 19 20
17 18 19 20 21 22 23  21 22 23 24 25 26 27  21 22 23 24 25 26 27
24 25 26 27 28 29 30  28                    28 29 30 31         
31                                                              
       April                  May                   June        
Su Mo Tu We Th Fr Sa  Su Mo Tu We Th Fr Sa  Su Mo Tu We Th Fr Sa
             1  2  3                     1         1  2  3  4  5
 4  5  6  7  8  9 10   2  3  4  5  6  7  8   6  7  8  9 10 11 12
11 12 13 14 15 16 17   9 10 11 12 13 14 15  13 14 15 16 17 18 19
18 19 20 21 22 23 24  16 17 18 19 20 21 22  20 21 22 23 24 25 26
25 26 27 28 29 30     23 24 25 26 27 28 29  27 28 29 30         
                      30 31                                     
        July                 August              September      
Su Mo Tu We Th Fr Sa  Su Mo Tu We Th Fr Sa  Su Mo Tu We Th Fr Sa
             1  2  3   1  2  3  4  5  6  7            1  2  3  4
 4  5  6  7  8  9 10   8  9 10 11 12 13 14   5  6  7  8  9 10 11
11 12 13 14 15 16 17  15 16 17 18 19 20 21  12 13 14 15 16 17 18
18 19 20 21 22 23 24  22 23 24 25 26 27 28  19 20 21 22 23 24 25
25 26 27 28 29 30 31  29 30 31              26 27 28 29 30      
                                                                
      October               November              December      
Su Mo Tu We Th Fr Sa  Su Mo Tu We Th Fr Sa  Su Mo Tu We Th Fr Sa
                1  2      1  2  3  4  5  6            1  2  3  4
 3  4  5  6  7  8  9   7  8  9 10 11 12 13   5  6  7  8  9 10 11
10 11 12 13 14 15 16  14 15 16 17 18 19 20  12 13 14 15 16 17 18
17 18 19 20 21 22 23  21 22 23 24 25 26 27  19 20 21 22 23 24 25
24 25 26 27 28 29 30  28 29 30              26 27 28 29 30 31   

筆記

這就是個純模擬的題,但看起來似乎很麻煩,且無從下手。

我們不妨從樣例輸出上入手,可發現大概可以將一張日曆劃分爲title和四個line,每個line包含三個block:

而每個block又可分爲三個部分:block_title、week_name、day。

可以看到,day的部分固定佔六行,每一個日期右對齊並佔兩位,兩個日期之間間隔一個空格,兩個block之間間隔兩個空格。

每月的首日前和最後一日後的日子要用空格填充。

由此,我們的任務就轉化爲如何依次輸出這三部分了。注意,由於控制檯的輸出特性,每行block的輸出是同時進行的。

可用三重循環來實現,一重循環控制line,一重循環控制block,一重循環控制一行day。

title、block_title、week_name

這三部分打印的內容是固定的,因此可以封裝爲函數直接調用。

有人會說每個line的block_title不同,其實這裏傳入一個行數參數即可進行統一控制:

void print_block_title(int i){
	switch(i){
		case 1:printf("      January               February               March        \n");break;
		case 2:printf("       April                  May                   June        \n");break;
		case 3:printf("        July                 August              September      \n");break;
		case 4:printf("      October               November              December      \n");break;		
	}
}

day

這塊是整道題中最不好打印的地方了。

步驟如下:

  1. 計算每個月首日是星期幾,記爲w[i];
  2. 月首之前空出的日子用空格填充;
  3. 一次輸出同一line中的每一行,共打印6行(分別輸出block1、block2、block3中的第一行,再輸出第二行,以此類推)。
  4. 月末之後空出的日子用空格填充。

使用數組d[i]跟蹤記錄輸出時每個block中的最新日期,若輸出日期值未超過當前月的最大天數,則輸出並增加1;否則輸出空格。

使用數組w[i]記錄每個block對應月份首日的星期,對應關係爲:{週日:0,週一:1,週二:2,週三:3,週四:4,週五:5,週六:6}。

使用數組m[i]記錄一個line中各個block對應的月份。

計算月首星期的方法

使用蔡勒公式(Zeller formula)來計算每個月第一天是星期幾。(注:蔡勒公式只能計算1582年後的日期)

公式如下:

其中:

w表示星期,取值範圍爲w={0,1,2,3,4,5,6},0爲星期日;

c表示世紀,y表示年分,d表示日;

m表示月份,取值範圍爲[3,14]內的整數。若被求月份爲1月和2月,要分別換算爲上一年的13月和14月

例如有日期2010-01-05,則c=20,y=10,m=13,d=5。

另外,符號“[ ]”表示向下取整。

在利用該公式代值計算時,要特別注意計算中出現負數的情況,建議按照以下步驟進行計算:

先計算

若w>=0,w = w%7;

否則,w = (w%7+7)%7。

月首和月末日期

每個月第一天之前和最後一天之後的日期要用空格補全。

找規律可知,第一天之前共有w[i]天,最後一天後有7-(w[i]+days[m[i]])%7天,其中days[i]表示第i月的天數,其它數組含義同上所述。

代碼

這裏的代碼是我自己寫的(已AC),不是標程

#include<stdio.h> 

int days[13]={-1,31,-1,31,30,31,30,31,31,30,31,30,31};//每月的天數 

void print_block_title(int i){
	switch(i){
		case 1:printf("      January               February               March        \n");break;
		case 2:printf("       April                  May                   June        \n");break;
		case 3:printf("        July                 August              September      \n");break;
		case 4:printf("      October               November              December      \n");break;		
	}
}
void print_week_name(){
	printf("Su Mo Tu We Th Fr Sa  Su Mo Tu We Th Fr Sa  Su Mo Tu We Th Fr Sa\n");
}
void print_title(int y){
	printf("                              %d                              \n\n",y);
}
/**
判斷是否閏年 
**/ 
int is_leap_year(int y){
	if(y%4==0 && y%100!=0 || y%400==0){
		return 1;
	}else{
		return 0;
	}
}

int max_r(int a, int b,int c){
	if(a>=b && a>=c){
		return a;
	}
	if(b>=a && b>=c){
		return b;
	}
	if(c>=a && c>=b){
		return a;
	}
}

/**
計算某個月的第一天是星期幾
return:星期(0:星期一,以此類推) 

note:使用蔡勒公式。1,2月要當成上一年的13,14月計算。 
**/
int day_of_first(int y,int m){
	if(m==1 || m==2){
		y--;
		m += 12;
	}
	int c = y/100;
	y %=100;
	int w = y+y/4+c/4-2*c+(26*(m+1)/10);
	if(w<0){
		w = (w%7+7)%7;
	}else{
		w %= 7;
	}
	return w;
}
int main(){
	int Y;
	while(scanf("%d",&Y)!=EOF){		
		
		//title
		print_title(Y);
		
		//block
		int line_i,j;
		int w[3];	//每個月的第一天是星期幾(0:星期日)
		int d[3];	//累計日期 
		int m[3];	//月份 
		for(line_i=1;line_i<=4;line_i++){	//循環打印每一行 			
			//初始化2月天數
			if(is_leap_year(Y)) {
				days[2] = 29;
			}else{
				days[2] = 28;
			}
			
			//初始化w、d、m數組
			int i;
			for(i=0;i<3;i++) {
				d[i] = 1;
				m[i] = (line_i-1)*3+i+1;
				w[i] = (day_of_first(Y,m[i]))%7;
			}
			
			//計算行數:不用算了,都是6行 
//			int r1 =  ((7-(w[0]+days[m[0]])%7)+w[0]+days[m[0]])/7;
//			int r2 =  ((7-(w[1]+days[m[1]])%7)+w[1]+days[m[1]])/7;
//			int r3 =  ((7-(w[2]+days[m[2]])%7)+w[2]+days[m[2]])/7;
//			int rows = max_r(r1,r2,r3);				
			
			print_block_title(line_i);
			print_week_name();			
			
			int block_i,row_i;
			for(row_i=0;row_i<6;row_i++){
				for(block_i=0;block_i<3;block_i++){
					if(block_i>0){
						printf("  ");
					}
					
					for(j=0;j<7;j++){
						if(j>0){
							printf(" ");
						}
						if(row_i==0 && j<w[block_i]){//填充空格 :只有第一行才需要填充空格 
							printf("  ");
						}else if(row_i>0 || row_i==0 && j>=w[block_i]){
							if(d[block_i]<=days[m[block_i]]){
								printf("%2d",d[block_i]);
								d[block_i]++;
							}else{
								printf("  ");
							}
						}
					}
				}
				
				printf("\n") ;
			}
		}
	}
	
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章