1.2 日期類問題

一、日期差值

1、題目和要求

時間限制:1s,內存限制:32MB,特殊判題:否
在這裏插入圖片描述

2、總結

1)閏年的判斷規則:當年數不能被100整除且能被4整除則爲閏年,或者其能被
400整除時也是閏年。某種情況下,可能出現兩個閏年相隔 8 年。

2)可以採用宏定義函數的方式判斷是否是閏年,宏定義函數的處理過程是:預處理器用複製宏代碼的方式代替函數的調用,省去了函數壓棧退棧過程,提高了效率。
#define ISYEAP(x) x%100!=0 && x%4==0 || x%400==0 ? 1:0

3)輸入技巧:輸入爲連續的八位數來表示日期,使用 %4d讀取前四位,使用 %2d%2d讀取其它後四位。省去了字符串處理。
scanf("%4d%2d%2d",&d.year,&d.month,&d.day);

4)由於需要計算輸入時間與規定的原點時間(規定爲0年0月0日)之間相差的天數,計算量較大,因此考慮對數據採用預處理的方式:

“在程序真正開始處理輸入數據之前,預處理出所有日期與原點日期之間的天數差並保存起來。當數據真正開始輸入時,只需要用0 (1) 的時間複雜度將保存的數據讀出,稍加處理便能得到答案。”

假定我們計算5001年12月31日之前的所有日期與原點日期之間的天數差,使用buf[5001][13][32]三維數組保存計算結果。這樣就可以直接使用下標buf[year][month][day]得到year年month月day日與原點日期之間的天數差。


在“4)”中,有以下幾點需要注意:

  1. 採用預處理空間換時間的重要手段(保存預處理所得數據所需的內存來換取實時處理所需要的時間消耗),酌情使用。
  2. buf[5001][13][32]這個數組比較耗費內存,因此需在函數體外定義,即定義成全局變量,或在函數中使用malloc等函數動態申請變量空間。
  3. 這種方法的一個缺點是,當輸入日期爲5002年的某一天時,將不能得出正確結果。

由於需要耗費大量的內存,若在main函數(其它函數也一樣(之中定義該數組,其函數所可以使用的棧空間將不足以提供如此龐大的內存,出現棧溢出,導致程序異常終止。所以,凡是涉及此類需要開闢大量內存空間的情況,都必須參照以上方法。


3、思路

考察了日期類問題中最基本的問題——求分別以兩個特定日期爲界的日期區間的長度。解決這類區間問題有一個統一的思想把原區間問題統一到起點確定的區間問題上。

在該例中,把問題統一到特定日期與一個原點時間的天數差,當要求兩個特定的日期之間的天數差時,只要將它們與原點日期的天數差相減,便能得到這兩個特定日期之間的天數差(必要時加絕對值)。

4、代碼
#include <iostream>
#include <string>
#include <cmath>
using namespace std;

struct Date{
	int year;
	int month;
	int day;
	
	Date(){
		year=0;month=0;day=0;
	}
}; 

int month(int i){
	switch(i){
		case 1:return 31;
		case 2:return 28;
		case 3:return 31;
		case 4:return 30;
		case 5:return 31;
		case 6:return 30;
		case 7:return 31;
		case 8:return 31;
		case 9:return 30;
		case 10:return 31;
		case 11:return 30;
		case 12:return 31;
	}
}

int calDays(Date *d){
	int days=0;
	int y_run = d->year/4,y_ping = d->year - y_run;
	//年 
	days = y_run*366+y_ping*365;
	//月 
	if(d->month>2){
		for(int i=1;i<=d->month;i++){
			days += month(i);
		}
		if((d->year % 4 ==0 && d->year % 100!=0) || d->year % 400 ==0){
			days += 1;
		}
	}
	//日
	days += d->day;
	return days; 
}

int main(){
	Date d1,d2;
	string s1,s2;
	int i=0;
//	cin>>s1>>s2;
	s1="20110412";
	s2="20110422";
	while(i<4) d1.year=d1.year*10+s1[i++];
	while(i<6) d1.month=d1.month*10+s1[i++];
	while(i<8) d1.day=d1.day*10+s1[i++];
	
	i=0;
	while(i<4) d2.year=d2.year*10+s2[i++];
	while(i<6) d2.month=d2.month*10+s2[i++];
	while(i<8) d2.day=d2.day*10+s2[i++];
	
	cout<<abs(calDays(&d1)-calDays(&d2))+1<<endl;
}
#include <stdio.h>
#include <iostream>
#include <cmath>
using namespace std;

#define ISYEAP(x) x%100!=0 && x%4==0 || x%400==0 ? 1:0
int buf[5001][13][32];

int dayOfMonth(int i,int isyeap){
	switch(i){
		case 1:return 31;
		case 2:
			if(isyeap){
				return 29;
			}
			return 28;
		case 3:return 31;
		case 4:return 30;
		case 5:return 31;
		case 6:return 30;
		case 7:return 31;
		case 8:return 31;
		case 9:return 30;
		case 10:return 31;
		case 11:return 30;
		case 12:return 31;
	}
}

struct Date{
	int year;
	int month;
	int day;
	
	Date(){
		year=0;month=0;day=0;
	}
	
	void nextDay(){
		day++;
		if(day>dayOfMonth(month,ISYEAP(year))){
			day=1;month++;
			if(month>12){
				month=1;year++;
			}
		}
	}
}; 


int main(){
	Date d1,d2;
	string s1,s2;
	int days=0;

	d1.day=1;d1.month=1;d1.year=0;
	while(d1.year!=5001){
		buf[d1.year][d1.month][d1.day]=days;
		d1.nextDay();
		days++;
	}
	//d1.year=2011;d1.month=4;d1.day=12;
	//d2.year=2011;d2.month=4;d2.day=22;
	scanf("%4d%2d%2d",&d1.year,&d1.month,&d1.day);
	scanf("%4d%2d%2d",&d2.year,&d2.month,&d2.day);
	printf("%d\n",abs(buf[d1.year][d1.month][d1.day]-buf[d2.year][d2.month][d2.day]))+1;
	return 0;
}

二、Day of Week

1、題目和要求

時間限制:1s,內存限制:32MB,特殊判題:否
在這裏插入圖片描述

2、總結

(4 + abs(calDays(&d1) - calDays(&d2)))%7 還可以寫成 ((4 + calDays(&d1) - calDays(&d2))%7 + 7)%7

3、思路

按照上面例題的解題思路:知道今天星期幾,知道今天和輸入天數相差幾天。根據星期以7天爲一週期,從而求得輸入日期是星期幾。

4、代碼
#include <cmath>
#include <string>
#include <iostream> 
using namespace std;

struct Date{
	int year;
	int month;
	int day;
	
	void setMonth(string s){
		if(s == "January") month = 1;
		else if(s == "February")month = 2;
		else if(s == "March")month = 3;
		else if(s == "April")month = 4;
		else if(s == "May")month = 5;
		else if(s == "June")month = 6;
		else if(s == "July")month = 7;
		else if(s == "August")month = 8;
		else if(s == "September")month = 9;
		else if(s == "October")month = 10;
		else if(s == "November")month = 11;
		else if(s == "December")month = 12;
		else month=0;
	}
};

int month(int i){
	switch(i){
		case 1:return 31;
		case 2:return 28;
		case 3:return 31;
		case 4:return 30;
		case 5:return 31;
		case 6:return 30;
		case 7:return 31;
		case 8:return 31;
		case 9:return 30;
		case 10:return 31;
		case 11:return 30;
		case 12:return 31;
	}
}

int calDays(Date *d){
	int days=0;
	int y_run = d->year/4,y_ping = d->year - y_run;
	//年 
	days = y_run*366+y_ping*365;
	//月 
	if(d->month>2){
		for(int i=1;i<=d->month;i++){
			days += month(i);
		}
		if((d->year % 4 ==0 && d->year % 100!=0) || d->year % 400 ==0){
			days += 1;
		}
	}
	//日
	days += d->day;
	return days; 
}

int main(){
	Date d1,d2;
	string m;
	d1.year=2020;d1.month=6;d1.day=4;
	
	cin>>d2.day>>m>>d2.year;
	d2.setMonth(m);

//2020.6.4 is Thursday
	switch((4+abs(calDays(&d1) - calDays(&d2)))%7){
		case 4: printf("Thursday\n");break;
		case 5: printf("Friday\n");break;
		case 6: printf("Saturday\n");break;
		case 0: printf("Sunday\n");break;
		case 1: printf("Monday\n");break;
		case 2: printf("Tuesday\n");break;
		case 3: printf("Wednesday\n");break;
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章