算法學習——日期處理問題

問題 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;
}

呼~終於搞定日期處理問題,下一節要學習進制轉換問題,但是最近要準備比賽啦,可能得拖幾天,好焦灼,加油加油~~~~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章