计算日期
计算日期是算法竞赛中比较基础的题型
聪明的笨办法
我们总是想着如何让程序运行的更快,而费尽心思减少运算量,却使我们的思路变得无比复杂,就像下面的代码,虽然能得到正确的答案,但是我们写起来会非常的消耗时间。
/*
有两个日期,求两个日期之间的天数,如果两个日期是连续的我们规定他们之间的天数为两天。
有多组数据,每组数据有两行,分别表示两个日期,形式为YYYYMMDD
每组数据输出一行,即日期差值
*/
/*
读入,拆分,判断大小(大年-小年,年相同看月)
相减,若年且二月不同,则分类讨论是否有闰年
*/
#include<cstdio>
#include<cstdlib>
#include<cstring>
int year1,year2,month1,month2,day1,day2;
int mon[12]={31,28,31,30,31,30,31,31,30,31,30,31};//存储每个月有几天
int rizi=0;
int is_Runyear(int);
void day(int,int);
void month(int,int);
void year(int,int);
void eql_year(int,int,int,int);
int main()
{
int a,b;
int flag=0;//闰年标志,☞1时为闰
scanf("%d\n%d",&a,&b);
if(a<b){
int tem;
tem=a;a=b;b=tem;
}
year1=a/10000; year2=b/10000;
month1=(a%10000)/100; month2=(b%10000)/100;
day1=a%100; day2=b%100;
//拆分完成,开始计算
//分类讨论,如果年月相同,计算日期即可
//年月相同
if(year1==year2&&month1==month2){
day(day1,day2);
printf("%d",rizi);
return 0;
}
//年相同
if(year1==year2){
eql_year(month2,month1,day2,day1);
printf("%d",rizi);
return 0;
}
//都不同
//开始计算前半部分
eql_year(month2,13,day2,0);//计算year2+1——year1-1年的日子再加上。。。
year(year2+1,year1);//中间部分计算完了
//计算后半部分
//在计算day的时候调用day会更新rizi的值
int rizi_tmp=rizi;
eql_year(month1,13,day1,0);//逆向一下,别忘了最后判断闰年
rizi=rizi_tmp+(365-rizi+1);
if(is_Runyear(year1)){
++rizi;
}
printf("%d",rizi);
system("pause");
return 0;
}
//判断是不是闰年
int is_Runyear(int year){
if(year%400==0){
return 1;
}
if((year%4==0)&&(year%100!=0)){
return 1;
}else{
return 0;
}
}
//计算计算天与天之间的差
void day(int a,int b){
rizi=a-b+1;
}
//计算月份之间的差
void month(int a,int b){
for(int i=a;i<b;i++){
rizi+=mon[i-1];
}
}
//计算年份之间的差
void year(int a,int b){
for(int i=a;i<b;i++){
rizi+=365+is_Runyear(i);
}
}
//年相同
void eql_year(int month2,int month1,int day2,int day1){
day(mon[month2-1],day2);
month(month2+1,month1);
rizi+=day1;
//判断是否与二月相关
if(month2<=2&&is_Runyear(year2)){
++rizi;
}
}
更合理的代码
计算机本就能够进行大量计算,我们就模拟真实世界时间的过去,那不就是初始日期+1+1+1,直到到达最终日期吗?因此最笨的办法就是从初始日期一天天加过去,到达最终日期,但是倘若时间相差1000年呢?这时候计算量就会非常的大,就会导致超时,因此我们可以在此基础上做一个小小的优化,我们可以将初始日期的年数加到最终日期的年数-1,这样将大大减少计算量,剩下的日期再一天一天加上去~
AC代码
#include<cstdio>
int month[14][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},{365,366}};
int is_run(int);
int main(){
int a,b;
while(scanf("%d%d",&a,&b)!=EOF){
if(a>b){
int tem;
tem=a;a=b;b=tem;
}
int year1,year2,month1,month2,day1,day2;//所有式子1<2
year1=a/10000,year2=b/10000,month1=(a%10000)/100,month2=(b%10000)/100,day1=a%100,day2=b%100;
int sum=1;//记录天数
for(;year1<year2-1;year1++){
sum+=month[13][is_run(year1)];
}
if(year1<year2&&month1<=month2){
sum+=month[13][is_run(year1)];
year1++;
}
while((month1!=month2)||(day1!=day2)){
if(day1==1+month[month1][is_run(year1)]){//一定不能忘记+1
month1++;
day1=1;
if(month1==13){
year1++;
month1=1;
}
if(month1==month2&&day1==day2){
break;
}
}
day1++;
sum++;
}
printf("%d\n",sum);
}
return 0;
}
int is_run(int year){
if((year%400==0)||(year%4==0)&&(year%100!=0)){
return 1;
}
return 0;
}
//假设year1month1day1<year2month2day2,且year1是闰年,month1day1是2月29日。
//我们不能武断的因为month1<month2,就把year1加到等于year2,因为year1,2月29日,当加到year2时,可能year2不是闰年,那么29这一天就不存在了
//或者说其实year2month2day1这一天应该被表示成year2的3月1日
//这就会造成无法跳出条件的死循环~
//好隐蔽的一个坑啊
注意我最后的注释,这里隐藏着一个坑,应该仔细思考一下~
假设year1month1day1<year2month2day2,且year1是闰年,month1day1是2月29日。我们不能武断的因为month1<month2,就把year1加到等于year2,因为year1,2月29日,当加到year2时,可能year2不是闰年,那么29这一天就不存在了或者说其实year2month2day1这一天应该被表示成year2的3月1日这就会造成无法跳出条件的死循环~
心德
在找不到bug的时候自己写几个测试数据,拟的时候多试试边界,这样就能发现一些写代码时没有注意到的点了~