CodeUp 1928 日期差值

计算日期

计算日期是算法竞赛中比较基础的题型

聪明的笨办法

我们总是想着如何让程序运行的更快,而费尽心思减少运算量,却使我们的思路变得无比复杂,就像下面的代码,虽然能得到正确的答案,但是我们写起来会非常的消耗时间。

/*
有两个日期,求两个日期之间的天数,如果两个日期是连续的我们规定他们之间的天数为两天。
有多组数据,每组数据有两行,分别表示两个日期,形式为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的时候自己写几个测试数据,拟的时候多试试边界,这样就能发现一些写代码时没有注意到的点了~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值