-1

私は現在USACOサイトで問題(13日の金曜日)に取り組んでおり、数値Nを指定して、1900年1月1日から12月までの各曜日に13日の金曜日が着陸する頻度を計算するプログラムをコーディングしました。 31st、1900 + N-1。アルゴリズムは暗算のトリックから着想を得ています:http ://www.jimloy.com/math/day-week.htm

注意点:1900年1月1日は月曜日でした。30日は、9月、4月、6月、11月で、残りはすべて31です。ただし、2月は28で、うるう年は29です。毎年、4で割り切れるのはうるう年です(1992 = 4 * 498なので、1992うるう年になりますが、1990年はうるう年ではありません)上記の規則は、1世紀の間は当てはまりません。400で割り切れる世紀の年はうるう年ですが、他のすべての年はうるう年ではありません。したがって、1700、1800、1900、および2100世紀はうるう年ではありませんが、2000年はうるう年です。*

プログラムは、N = 256(1900〜2156)の場合を除いて正常に動作します。私のプログラム出力:440 438 439 439 437 439 440

USACOにいる間、次のようになります:440 439 438 438 439 439 439

プログラムは、入力としてNを含むファイル(friday.in)を受け取り、別のファイル(friday.out)の1行に各日(土曜日から開始)の発生数を表す7つのスペース区切りの整数を出力します。

デバッグのためにいくつかのcoutを配置しました。

コードは次のとおりです。

/*
ID: freebie1
PROG:friday
LANG: C++
*/

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

class Date
{
    public:
    Date(int month=0,int year=0):m_month(month),m_year(year)
    {

    }
    int monthDiff()
    {
        if(m_month<=3)
        {
            if(m_month==1)
            {
                    return 0;
            }
            else if(m_month==2)
            {
                    return 31;
            }
        }
        if(m_month>=3)
        {
            if((m_year%4==0 && m_year%100!=0)||(m_year%100==0 && m_year%400==0))
            {
                if(m_month<9)
                {
                    if(m_month%2==0)
                        return 60+(31*int(m_month/2.6)+30*(int(m_month/2.6)-1));
                    else
                        return 60+(61*int(m_month/3.5));

                }

                else if(m_month>=9)
                {

                    if(m_month%2==0)
                        return 91+61*(m_month/3);
                    else
                        return 91+(31*int(m_month/2.75)+30*int(m_month/3.6));
                }
            }
            else
            {
                if(m_month<9)
                {
                    if(m_month%2==0)
                        return 59+(31*int(m_month/2.6)+30*(int(m_month/2.6)-1));
                    else
                        return 59+(61*int(m_month/3.5));

                }

                else if(m_month>=9)
                {

                    if(m_month%2==0)
                        return 90+61*(m_month/3);
                    else
                        return 90+(31*int(m_month/2.75)+30*int(m_month/3.6));
                }
            }

        }
    }
    void show()
    {
        cout<<m_month<<"/"<<m_year<<": ";
    }
    int tellDay()
    {
        int daysInYears=int((m_year-1900))*365;
        int daysInMonths=this->monthDiff();
        int leapDays;
        if(m_year%4==0 && m_year!=1900)
            leapDays=int((m_year-1900)/4)-1;
        else if(m_year>2100)
            leapDays=int((m_year-1900)/4)-1;
        else if(m_year>2200)
            leapDays=int((m_year-1900))/4-2;
        else
            leapDays=int((m_year-1900))/4;

        int days=13+leapDays;
        int res=daysInYears+daysInMonths+days;
        cout<<"MonthDiff: "<<this->monthDiff()<<" In years: "<<daysInYears<<" days: "<<days<<"   ";
        return res%7;
    }
    private:
    int m_month;
    int m_year;
};

int main()
{
    ifstream fin("friday.in");
    ofstream fout("friday.out");

    if(fin)
    {
        int n(0),day(0),sMonth(1),sYear(1900);
        fin>>n;
        vector<int> weekDays(7,0);
        for(int i(0);i<n;i++)
        {
            for(int j(0);j<12;j++)
            {
                Date date(sMonth+j,sYear+i);
                day=date.tellDay();
                date.show();
                cout<<day<<endl;
                switch(day)
                {
                    case 0:
                    weekDays[1]+=1;
                    break;
                    case 1:
                    weekDays[2]+=1;
                    break;
                    case 2:
                    weekDays[3]+=1;
                    break;
                    case 3:
                    weekDays[4]+=1;
                    break;
                    case 4:
                    weekDays[5]+=1;
                    break;
                    case 5:
                    weekDays[6]+=1;
                    break;
                    case 6:
                    weekDays[0]+=1;
                    break;
                }

            }

        }
        for(int i(0);i<6;i++)
        {
            fout<<weekDays[i]<<" ";
        }
        fout<<weekDays[6]<<endl;
    }

    return 0;
}
4

1 に答える 1

1

205 年後、つまり 2104 年から間違った結果が得られます。

if(m_year%4==0 && m_year!=1900)
    leapDays=int((m_year-1900)/4)-1;

4 で割り切れる年については、うるう年でない 2100 年、2200 年、2300 年、2500 年などをカウントから引きません。

修理:

if(m_year%4==0 && m_year!=1900)
    leapDays=int((m_year-1900)/4)-1 + (m_year-1604)/400 - (m_year-1904)/100;

それらを減算します。これにより、2300 年以降の 4 で割り切れない年のうるう年のカウントが間違ったままになります。同様の修正を追加することで修正できます (その場合、複数のブランチは必要ありません)。

else
    leapDays=int((m_year-1900)/4) + (m_year-1600)/400 - (m_year-1900)/100;

この式は、 1900 からまでの間に経過した閏年の数を決定するものとしm_yearます。が 4 の倍数でない場合m_year、単純な「4 の倍数はうるう年」で、 とカウントされ(m_year - 1900)/4ます。ただし、100 の倍数は一般に閏年ではないことを考慮していないため、その間に経過した閏年の数を差し引き- (m_year - 1900)/100ます。ただし、うるう年である 400 の倍数も差し引かれているため、それらのカウントを元に戻します(+ (m_year - 1600)/400ここでの基準年は 1600 で、1900 年以降では最大の 400 の倍数です)。

4 の倍数の場合、現在の年がうるう年ではなく、現在の年よりもに修正する必要があるため、修正を後でのみ行い、基準年をシフトします。

より良い修正、うるう年のカウントを均一にする (分岐なし):

int leapDays = (m_year - 1901)/4 + (m_year-1601)/400 - (m_year-1901)/100;
于 2012-07-30T23:10:54.747 に答える