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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章