Задача из проекта Эйлера, 19 - сколько воскресеньям пал на первый


Вот проблема:

Сколько воскресеньям пришелся на первое число месяца в двадцатом века (1 января 1901 по 31 декабря 2000 года)?

И вот мой код:

#include <stdio.h>

int main(void){
    int months[12] = { 31 , 28 , 31 , 30 , 31 , 30 , 31 , 31 , 30 , 31 , 30 , 31 };
    int year=1901;
    int dayoftheweek=2;  //put a 2 because the 1 jan 1901 is tuesday. 0-sunday 6-Saturday
    int sunday=0;
    int firstsundays=0;

    while(year<=2000){
        if(year%4==0)    //checking if it's a leap year
            months[1]=29;

        for (int i = 0; i < 12; ++i) {
            for (int d = 1; d <= months[i]; d++){
                if(dayoftheweek==7)  //reset the week
                    dayoftheweek=0;

                if(dayoftheweek==sunday && d==1)
                    firstsundays++;

                dayoftheweek++;
            }
        }

        months[1]=28;
        year++;
    }

    printf("There are %d Sundays that fell on the first of the month\n", firstsundays);

    return 0;
}

Что я мог бы улучшить?



512
5
задан 25 января 2018 в 10:01 Источник Поделиться
Комментарии
1 ответ

Петель может быть яснее:


  • Крайние петли фактически распределяется по трем направлениям: int year=1901, while(year<=2000)и year++. Он должен быть написан как for петли.

  • i должен быть переименован в month или m.

  • Исключительный случай для високосных лет-то неудобно: вы иногда колошматят февраля запись в верхней части петли, затем сбросить его в конце. Я считаю таких мутаций быть хак, который делает код труднее понять. Это также делает код труднее поддерживать, так как у вас жестко 29 и 28 в разбросанных местах.

Что касается самого алгоритма... вы должны быть в состоянии сделать лучше, чем наступал день, через целые века. Почему не заранее месяца за раз?

#include <stdio.h>

static const int *month_lengths(int year) {
static const int NON_LEAP_YEAR[] = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
static const int LEAP_YEAR[] = {
31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ?
LEAP_YEAR : NON_LEAP_YEAR;
}

int main(void) {
int first_sundays = 0;
int day_of_the_week = 2; // 0 = Sun, 6 = Sat. 1 Jan 1901 was a Tuesday.
for (int year = 1901; year <= 2000; ++year) {
const int *lengths = month_lengths(year);
for (int month = 0; month < 12; month++) {
if (day_of_the_week == 0) {
first_sundays++;
}
day_of_the_week = (day_of_the_week + lengths[month]) % 7;
}
}
printf("There are %d Sundays that fell on the first of the month\n",
first_sundays);
}

5
ответ дан 26 января 2018 в 12:01 Источник Поделиться