算法学习——日期处理问题

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Marilynmontu/article/details/81197197

问题 A: 日期差值
时间限制: 1 Sec 内存限制: 32 MB
题目描述
有两个日期,求两个日期之间的天数,如果两个日期是连续的我们规定他们之间的天数为两天。

输入
有多组数据,每组数据有两行,分别表示两个日期,形式为YYYYMMDD

输出
每组数据输出一行,即日期差值

样例输入
20130101
20130105
样例输出
5
解题思路
这种求日期之间相差天数的题目有一个很直接的思路,即令日期不断加1天,直到第一个日期等于第二个日期为止,即可统计出答案。具体处理时,如果当天加了一天会后天数等于当前月份所拥有的天数加1,那么就令月数加1,同时置天数为1号(等同于把日期变为下一个月的1号);如果此时月份变为了13,那么就令年份加1,同时置月份为1月(则日期变为下一年的1月)。
为了方便直接取出每个月的天数,不妨给定一个二维数组来存放每个月的天数,其中第二维为0时表示平年,为1时表示闰年。
此处为了加快速度,先把第一个日期的年份不断加1,直到与第二个日期的年份相差1为止,期间根据平年或闰年来累加365天或366天。之后再进行天数不断加1直到与第二个日期相等。

Submission

#include <stdio.h>
int month[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}};
//平年和闰年的每个月的天数
int isLeap(int year){//判断是否为闰年
    return(year%4==0&&year%100!=0 || year%400==0);
}
int main() {
    int time1,time2,y1,y2,m1,m2,d1,d2;
    while(scanf("%d%d",&time1,&time2)!=EOF){
        if(time1>time2){//第一个日期晚于第二个日期则交换
            int temp=time1;
            time1=time2;
            time2=temp;
        }
   //计算出两个日期对应的年月日
    y1=time1/10000,y2=time2/10000;
    m1=time1%10000/100,m2=time2%10000/100;
    d1=time1%100,d2=time2%100;
    int sum=1;//记录天数
    while(y1<y2-1){//把第一个日期的年份不断加1,直到与第二个年份相差1为止
        if(isLeap(y1)){//判断是平年或闰年来累加365天或者366天
            sum+=366;
        }
        else{
            sum+=365;
        }
        y1++;
    }
    //第一个日期没有达到第二个日期时进入循环
    while(y1<y2||m1<m2||d1<d2){
        d1++;
        if(d1==month[m1][isLeap(y1)]+1){//满当月天数
            m1++;//日期变为下个月1号
            d1=1;
        }
        if(m1==13){//月份满12个月
            y1++;//日期变为下一年的1月
            m1=1;
        }
        sum++;//累计天数
    }
    printf("%d\n",sum);//输出结果
}
    return 0;
}

第二种方法是先将0~5000年12月31日的所有数据预处理一下,之后就可以直接拿来用了,很方便。这里的三维数组一定要定义到主函数外,不然估计会有数组越界的问题。因为写B题时沿用了A题的方法一导致超时,所以才找到了这个方法。但是这个方法不适用于没有告诉你年份区间的题目,这样5000年的范围对测试数据来说可能根本不够。

Submission

#include <iostream>
#include <stdio.h>
#define isyear(x) x%100!=0 && x%4==0 || x%400==0?1:0
using namespace std;

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 E{
    int day;
    int month;
    int year;
    void nextday(){
        day++;
        if(day>dayofMonth[month][isyear(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(){
    E tmp;
    int cut = 0;
    tmp.year = 0;
    tmp.month = 1;
    tmp.day = 1;
    while (tmp.year!=5000){
        buf[tmp.year][tmp.month][tmp.day] = cut;
        tmp.nextday();
        cut++;
    }
    int y1,m1,d1,y2,m2,d2;
    while (scanf("%4d%2d%2d",&y1,&m1,&d1)!=EOF){
        scanf("%4d%2d%2d",&y2,&m2,&d2);
        printf("%d\n",abs(buf[y2][m2][d2]-buf[y1][m1][d1])+1);

    }


    return 0;
}

问题 B: Day of Week
题目描述
We now use the Gregorian style of dating in Russia. The leap years are years with number divisible by 4 but not divisible by 100, or divisible by 400.
For example, years 2004, 2180 and 2400 are leap. Years 2004, 2181 and 2300 are not leap.
Your task is to write a program which will compute the day of week corresponding to a given date in the nearest past or in the future using today’s agreement about dating.

输入
There is one single line contains the day number d, month name M and year number y(1000≤y≤3000). The month name is the corresponding English name starting from the capital letter.

输出
Output a single line with the English name of the day of week corresponding to the date, starting from the capital letter. All other letters must be in lower case.

样例输入
21 December 2012
5 January 2013
样例输出
Friday
Saturday
解题思路
用第一题的思路,处理好输入输出的格式,也是计算两个日期之间的差值,第二个日期可以设置为编程的日期或者某一组测试数据的日期。
Submission

#include <stdio.h>
#include <string.h>
#define isleap(x) (x % 100 != 0 && x % 4 == 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}};

char dayofWeek[7][20] = {"Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"};

char monthofYear[13][20] = {"","January","February","March","April","May",
                            "June","July","August","September","October","November","December"};

int cordOfDate(int year1,int month1,int day1){
    int year2 = 2013;
    int month2 = 1;
    int day2 = 5;
    int tempY,tempM,tempD;
    int cnt = 0;
    int num1 = year1*10000 + month1*100 + day1;
    int num2 = year2*10000 + month2*100 + day2;

    if(num1 > num2){
        tempY = year1;
        tempM = month1;
        tempD = day1;
        year1 = year2;
        month1 = month2;
        day1 = day2;
        year2 = tempY;
        month2 = tempM;
        day2 = tempD;
    }

    while(year1 < year2 || month1 < month2 || day1 < day2){
        day1++;
        if(day1 == dayofMonth[month1][isleap(year1)] + 1){
            month1++;
            day1 = 1;
        }

        if(month1 == 13){
            year1++;
            month1 = 1;
        }
        cnt++;
    }

    return cnt;
}


int main()
{
    int day,year;
    char month[20];
    int num,n;
    int i;
    while(scanf("%d %s %d",&day,month,&year) != EOF){
        for(i = 0;i < 14;i++){
            if(strcmp(month,monthofYear[i]) == 0){
                num = i;
                break;
            }
        }
        n = cordOfDate(year,num,day);
        printf("%s",dayofWeek[(n+5) % 7]);
    }
    return 0;
}

上面的方法总是超时,希望大家帮我看看为啥。。然后就找了下面这种方法,成功过了。

#include <iostream>
#include <stdio.h>
#include <string.h>
#define isyear(x) x%100!=0 && x%4==0 || x%400==0?1:0
using namespace std;

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,

};
char Months[13][20]={
    "","January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
}; 
char Weeks[7][20]={
        "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
};

struct E{
    int day;
    int month;
    int year;
    void nextday(){
        day++;
        if(day>dayofMonth[month][isyear(year)]){
            day =1;
            month++;
            if(month>12){
                month=1;
                year++;
            }
        }
    }
};
int buf[3001][13][32];
int main(){
    E tmp;
    int cut = 0;
    tmp.year = 0;
    tmp.month = 1;
    tmp.day = 1;
    int days;
    int y1=2018,m1=4,d1=15,y2,d2;
    char S[20];
    while (tmp.year!=3001){
        buf[tmp.year][tmp.month][tmp.day] = cut;
        tmp.nextday();
        cut++;
    }
    int i;
    while (scanf("%d%s%d",&d2,S,&y2)!=EOF){
        for( i=1;i<=12;i++){
            if(strcmp(S,Months[i])==0){
                break;
            }
        }
         days = buf[y2][i][d2] - buf[2012][7][16];
         days+=1;
         cout<<Weeks[(days%7+7)%7]<<endl;

    }


    return 0;

}

问题 C: 打印日期
题目描述
给出年分m和一年中的第n天,算出第n天是几月几号。

输入
输入包括两个整数y(1<=y<=3000),n(1<=n<=366)。

输出
可能有多组测试数据,对于每组数据,按 yyyy-mm-dd的格式将输入中对应的日期打印出来。

样例输入
2013 60
2012 300
2011 350
2000 211
样例输出
2013-03-01
2012-10-26
2011-12-16
2000-07-29

解题思路
可以采用累加的方法从该年的第一天加起,直到等于输入的天数,虽然可行但是比较慢,如果输入的天数是365天就要累加365次。故可一个月一个月的累加,判断累加结果是否等于输入的天数。或者一个月一个月的累减,判断累减结果是否小于等于0来判断月份天数。此题应该注意输出格式,要求按 yyyy-mm-dd的格式将输入中对应的日期打印出来,可以用%0md实现,其用法如下。
(1)%md
%md可以试不足m位的int型变量以m位进行右对齐输出,其中高位用空格补齐;如果变量本身超过m位,则保持原样。
(2)%0md
%0md只是在%md中间多加了0。和%md唯一不同点在于,当变量不足m位时,将在高位补足够数量的0而不是空格。

Submission

#include <stdio.h>
#define isleap(x) (x % 100 != 0 && x % 4 == 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}};

int main()
{
    int day1,month1,year1;
    int flag,i;
    while(scanf("%d%d",&year1,&day1) != EOF){
        flag=isleap(year1);
        for(i=1;i<=12;i++){
        if(day1-dayofMonth[i][flag]<=0) break;
        else day1-=dayofMonth[i][flag];
        }
        printf("%04d-%02d-%02d\n",year1,i,day1);
    }
    return 0;
}

问题 D: 日期类
题目描述
编写一个日期类,要求按xxxx-xx-xx 的格式输出日期,实现加一天的操作。

输入
输入第一行表示测试用例的个数m,接下来m行每行有3个用空格隔开的整数,分别表示年月日。测试数据不会有闰年。

输出
输出m行。按xxxx-xx-xx的格式输出,表示输入日期的后一天的日期。

样例输入
2
1999 10 20
2001 1 31
样例输出
1999-10-21
2001-02-01
提示
注意个位数日期前面要有0。

解题思路
这道题思路很常规,天数加1判断是否超过当月总天数,超过则月份加1,天数置1;再判断月数是否超过一年的总月份(12个月),超过则年份加1,月份置1。

Submission

#include <stdio.h>
#define isleap(x) (x % 100 != 0 && x % 4 == 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}};

int main()
{
    int day1,month1,year1;
    int flag,n;
    scanf("%d",&n);
    while(n--){
        scanf("%d%d%d",&year1,&month1,&day1);
        flag=isleap(year1);
        day1++;
        if(day1>dayofMonth[month1][flag]){
            month1++;
            day1=1;
            if(month1>12){
                year1++;
                month1=1;
            }
        }
        printf("%04d-%02d-%02d\n",year1,month1,day1);

    }
    return 0;
}

问题 E: 日期累加
题目描述
设计一个程序能计算一个日期加上若干天后是什么日期。

输入
输入第一行表示样例个数m,接下来m行每行四个整数分别表示年月日和累加的天数。

输出
输出m行,每行按yyyy-mm-dd的个数输出。

样例输入
1
2008 2 3 100
样例输出
2008-05-13

解题思路
这道题其实和C题类似,不过这儿的天数可以大于365或者366。 将天数缩小到一年(365或366天)内。判断当前年份是否为闰年,是则年份加1,天数减366;反之则年份加1,天数减365,直到天数小于当前年份一年中总天数。
其次,将天数累加到当前日期,开始累减,直到当前日期中的日数小于当前月份的总天数。判别条件见代码。

Submission

#include <stdio.h>
#define isleap(x) (x % 100 != 0 && x % 4 == 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}};
int dayofYear[2]={365,366};
int main()
{
    int day1,month1,year1,day;
    int flag,i,n;
    scanf("%d",&n);
    while(n--){
        scanf("%d%d%d%d",&year1,&month1,&day1,&day);
            for(;;){//将需要累加的天数缩小为一年之内
                flag=isleap(year1);
                if(day-dayofYear[flag]>=dayofYear[flag]){
                    year1++;
                    day-=dayofYear[flag]; 
                } 
                else break;
            }
            day1+=day;
            for(;;){//将缩小后的天数累加
                flag=isleap(year1);
                if(day1>dayofMonth[month1][flag]){
                    day1-=dayofMonth[month1][flag];
                    month1++;
                    if(month1>12){
                        year1++;
                        month1=1;
                    }
                }
                else break;
            }
            printf("%04d-%02d-%02d\n",year1,month1,day1);
        }
    return 0;
}

呼~终于搞定日期处理问题,下一节要学习进制转换问题,但是最近要准备比赛啦,可能得拖几天,好焦灼,加油加油~~~~

猜你喜欢

转载自blog.csdn.net/Marilynmontu/article/details/81197197