例2.3 日期差值(九度教程第6题)
题目
时间限制:1 秒 内存限制:32 兆 特殊判题:否
题目描述:
有两个日期,求两个日期之间的天数,如果两个日期是连续的我们规定他们之间的天数为两天
输入:
有多组数据,每组数据有两行,分别表示两个日期,形式为YYYYMMDD
输出:
每组数据输出一行,即日期差值
样例输入:
20110412
20110422
样例输出:
11
来源:
2009年上海交通大学计算机研究生机试真题
解析:
该例题考察了日期类问题中最基本的问题:求两个日期间的天数差。
解决这类区间问题有一个统一的思想:把原区间问题统一到起点确定的区间问题上去。这样做有一个巨大的好处:预处理,可以在程序真正开始处理输入数据之前,预处理出所有日期与原点日期的天数差并保存起来。
所以统一设一个原点时间:如0000年1月1日。当要求两个特定日期的天数差时,只要将它们与原点日期的天数差相减,便能得到这两个特定日期之间的天数差(必要时加绝对值)。
还需注意:闰年。
注:
1,定义了一个类,可以用来表示日期,还可以自动计算出下一个日期。
2,为了判断该年是否为闰年,定义了一个宏。
3,保存某特定日期与原点日期的天数差时,使用了三维数组,用年、月、日分别表示该数组下标。这将日期本身与其存储地址联系了起来,只需直接利用它的年月日数字即可找到保存的值。(将数据本身与数据存储地址联系起来,这是Hash的思想,也是Hash的一种基本方式。)
4,输入采用了某种技巧。使用%4d来读取该八位数的前四位并赋值给代表年的变量。 利用在%d之间插入数字来读取特定位数的数字的技巧,值得去采用。
5,将buf[5001][13][32]这个相对比较耗费内存的数组定义为全局变量,是有原因的。 由于需要耗费大量内存,若在main函数中定义该数组,该函数所使用的栈空间不足以提供如此庞大的内存,出现栈溢出,导致程序异常终止。
因此,今后凡是涉及此类需要开辟大量内存空间的情况,必须在函数main体外定意,即定义为全局变量。或者在函数中使用malloc等函数动态申请变量空间。
大致思路:
自定义结构体Date、自定义一个时间原点(0年1月1日)、预存每月的天数(二月作特殊处理),预处理出所有日期与原点日期的天数差,保存在一个三维数组buf[][][]中。
输入要计算的两个日期,求对应两个buf[][][]值的绝对值即可。
代码:
#include<stdio.h>
//定义宏判断是否为闰年,方便计算每月天数
#define IsYeap(x) x%4==0 && x%100!=0 || x%400==0 ?1:0
int dayOfMonth[13][2]={
0,0,
31,31,
28,29,
31,31,
30,30,
31,31,
30,30,
31,31,
31,31,
30,30,
31,31,
30,30,
31,31
};//预存每月的天数,注意二月作特殊处理
struct Date{ //日期类,方便日期的推移
int day;
int month;
int year;
void nextDay(){//计算下一天的日期
day++;
if(day>dayOfMonth[month][IsYeap(year)])//若日数超过了当月最大天数
{
day=1;
month++; //进入下一月
if(month>12){
month=1;
year++;//进入下一年
}
}
}
};
int buf[5001][13][32];//保存预处理的天数
int Abs(int x){ //求绝对值
return x<0?-x:x;
}
int main()
{
Date tmp;
int cnt=0; //天数计数
tmp.day=1;
tmp.month=1;
tmp.year=0; //初始化日期类对象为0年1月1日
while(tmp.year!=5001){//日期不超过5000年
buf[tmp.year][tmp.month][tmp.day]=cnt; //将该日与0年1月1日的天数差保存起来
tmp.nextDay(); //计算下一天日期
cnt++; //计数器累加代表与原点日期的间隔又增加一天
}
int d1,m1,y1;
int d2,m2,y2;
while(scanf("%4d%2d%2d",&y1,&m1,&d1)!=EOF){
scanf("%4d%2d%2d",&y2,&m2,&d2);//读入要计算的两个日期
printf("%d\n",Abs(buf[y1][m1][d1]-buf[y2][m2][d2])+1);
}
return 0;
}