日歷問題詳解-CCF-CSP練習題(100)


目錄

題目:

分析:

C++ STL代碼:

總結:


來自湖大程序設計訓練系統(外網進不去,所以不貼鏈接了)。

題目:

日歷問題
問題描述 在我們先在使用的日歷中,閏年被定義為能被4整除的年份,但是能被100整除而不能被400整除的年是例外,他們不是閏年。例如:1700,1800,1900和2100年不是閏年,而1600,2000和2400是閏年。給定從公元2000年1月1日開始逝去的天數,你的任務是給出這一天是哪年哪月哪日星期幾
輸入數據 輸入包含若干行,每行包含一個正整數,表示從2000年1月1日開始逝去的天數。輸入最后最后一行是-1,不必處理。可以假設結果的年份不會超過9999. 
輸出要求

對每個測試樣例,輸出一行,該行包含對應的日期和星期幾。合適為“YYYY-MM-DD DayOfWeek”。其中“DayOfWeek”必須是下面中的一個:“Monday”,“Tuesday”,“Wednesday”,“Thursday,“Friday”,“Saturday”,“Sunday”。

輸入樣例

1730
1740
1750
1751

-1

輸出樣例 2004-09-26 Sunday
2004-10-06 Wednesday
2004-10-16 Saturday
2004-10-16 Sunday

分析:

首先這道題看着很復雜,因為涉及閏年和平年天數不一樣,閏年366天,2月為29天;平年365天,2月為28天。而且每月的天數也不相同,1、3、5、7、8、10、12月為31天,4、6、9、11月為30天,沒有太大的規律可循,所以不能用 逝去的天數  取余一年的天數 。只有星期是每星期都是7天,所以可以用  逝去的天數  取余  7來判斷星期幾。

首先我們可能想到最蠢的辦法一天一天判斷,每到7天星期歸0,每到月末月數+1,每到12月年數+1,月數歸1.但這個辦法太蠢,如果7000年的話得算到啥時候。

所以我們可能會想到先判斷是哪一年,再判斷是哪一月,再計算出是哪一天,最后計算是星期幾。在年和月判斷的時候最開始我們可能是想到用if()else語句,先判斷剩余天數是否大於當前年所有天數(閏年366天,平年365天),然后再判斷如果是閏年則減去366天,如果是平年則減去365天。最后剩余天數是不夠一年所含天數的,所以年份算出來了。同樣可以循環判斷求出所在月份。最后天數+1就可以了。

那么問題來了,我們怎么判斷年份是閏年還是平年,怎么判斷月份的天數,我們可能想到用if()else語句來判斷,那么我們每次都要判斷一下,如果我們事先將一年中每月所含天數用一個數組存起來的話是不是更方便判斷,同樣,我們是不是也可以用數組將星期幾也存進去。所以我們選擇數組存儲年份所含天數,月份所含天數,星期幾字符串。

最后,上面我們是一年一年判斷,然后減去年份天數(366/365),那我們在判斷一年是閏年后,我們是不是可以肯定接下來的3年都是平年,如果剩余天數夠的話我們是不是就可以直接減去3*365天。然后再判斷是否是閏年。這樣運行時間又能變為原來1/4。

注意:天數最后要+1;要用取余(%)判斷是否是閏年;輸出格式要控制好,日期格式是2000-09-01,如過剩余天數是個位數,則要在前邊加上0,具體做法可以參照下面代碼,C++控制數據按照指定位數輸出,主要用到C++兩個輸出控制,setw(位數),和setfill(指定字符)。需要加上頭#include <iomanip>。

cout << setw(2) << setfill('0') <<month << '-' << setw(2) << setfill('0') << day+1 << ' ' ;

C++ STL代碼:

#include <iostream>
#include <vector>
#include <iomanip>
using namespace std;

int main()
{
    int yType(int y);/*判斷年份是潤年還是平年的函數,返回0是平年,返回1表示是潤年*/
    vector<int> elapseDay;/*由於沒有具體說明測試多少個,所以用動態存儲vector存放逝去的天數列表*/
    int monthOfY[2][13] = { {0,31,28,31,30,31,30,31,31,30,31,30,31},
                            {0,31,29,31,30,31,30,31,31,30,31,30,31}
                        };//monthOfY[0]表示平年每月天數,monthOfY[1]表示閏年每月天數
    char weeks[7][12] = {"Saturday","Sunday","Monday", "Tuesday", "Wednesday", "Thursday", "Friday" };/*星期字符串,2000年1月1號是周六,所以從周六開始*/
    int year = 2000;/*當前年份*/
    int yd[2] = {365,366};/*yd[1]表示潤年,yd[0]表示平年*/
    int month = 0;/*月份*/
    int day = 0;/*存儲逝去的天數*/
    int week = 0;/*標識星期幾*/

    int temp;/*暫存中間變量*/
    int yT = 0;  /*標識平年還是潤年*/

    while(1)/*從輸入流讀入逝去的天數*/
    {
        cin >>temp;
        if(-1 == temp){
            break;
        }
        elapseDay.push_back(temp);/*將temp插入到elapseDay末尾*/
    }
    vector<int>::iterator i = elapseDay.begin();/*迭代器遍歷vector*/
    for( ;i != elapseDay.end(); i++)/*循環輸出每個逝去的天數對應的日期*/
    {
        day = *i;

        week = day%7; /*計算星期幾*/

        for(year=2000; day >= yd[yT=yType(year)]; year ++)/*從2000年開始,算出當前年份,從yType()函數處可得知本年屬於平年還是潤年*/
        {
            day -= yd[yT];/*減去本年天數*/
            /*day -= 365*3;
              year +=3;
            */
        }

        for(month = 1; day >= monthOfY[yT][month]; month++)/*month對應月份,判斷當前剩余天數是否大於本月所含天數,小於的話就退出for循環*/
        {
            day -=monthOfY[yT][month]; /*day是剩余天數,每次循環減去本月天數*/
        }
        cout << year << '-' ;
        cout << setw(2) << setfill('0') <<month << '-' << setw(2) << setfill('0') << day+1 << ' ' ; /*控制輸出位數,保證輸出格式和要求一致*/
        cout << weeks[week]  <<endl;

    }
    return 0;
}

int yType(int y)/*判斷y年份是平年還是潤年*/
{
    if( (y%400==0) || (y%4==0 && y%100!=0) )/*如果能被400整除的話就不用判斷后邊的了,否則判斷是否是能被4整除不能被100整除*/
            {
                return 1;/*是潤年*/
            }else{
                return 0;/*不是潤年*/
            }
}

總結:

在答題的過程中要仔細閱讀題目,首先分析可以使用什么數據結構來存題目中出現的數據,然后再分析此種數據結構是否可行,不行的話換個數據結構。就這樣What(用什么數據結構),Why(為什么用這種數據結構,有什么好處)不斷重復優化。這些在寫公司面試題或者要求時間空間效率的時候是比較好的方法。在做CCF-CSP考試前兩題的時候估計幾乎不怎么用,只要把題做出來,能得滿分就行,對於代碼風格,時間空間效率只要滿足條件就行,要求不太苛刻。

題目中充分利用了數組,不少題目都可以很巧妙的應用數組,比如CCF-CSP2013-12-1這道題,詳見稍后再寫。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM