segunda-feira, 16 de maio de 2016

Resposta do problema 19 - Counting Sundays

O objetivo desse problema é somar quantos domingos aconteceram no primeiro dia do mês entre as datas: 01/01/1901 e 31/12/2000 usando apenas as informações passadas que são:

  • 01/01/1900 foi uma segunda-feira
  • 30 dias tem setembro, abril, junho e novembro
  • todos os outros meses tem 31 exceto fevereiro que pode ter 28 ou 29 (quando for bissexto)
  • o ano bissexto ocorre em todos os anos divisíveis por 4 exceto na virada do século, a menos que esse ano seja divisível por 400

Se fosse para usar as bibliotecas de data de qualquer linguagem esse problema seria muito simples, mas o objetivo é fazer com que o programador crie uma lógica apenas com as informações passadas.
You are given the following information, but you may prefer to do some research for yourself.
  • 1 Jan 1900 was a Monday.
  • Thirty days has September,
  • April, June and November.
  • All the rest have thirty-one,
  • Saving February alone,
  • Which has twenty-eight, rain or shine.
  • And on leap years, twenty-nine.
  • A leap year occurs on any year evenly divisible by 4, but not on a century unless it is divisible by 400.
How many Sundays fell on the first of the month during the twentieth century (1 Jan 1901 to 31 Dec 2000)?
Link para a pergunta: https://projecteuler.net/problem=19 

Criei o seguinte script para resolver o problema;
#Retorna true se o ano é bissexto e false se não for
def is_leap_year(ano):
 if (ano % 2 != 0):
  return False
 else:
  if (ano % 100 == 0):
   if (ano % 400 == 0):
    return True
   else:
    return False
  else:
   if (ano % 4 == 0):
    return True
   else:
    return False

dia_semana = 1 # 1 = segunda-feira / 7 = domingo
total_domingo_inico_mes = 0

def proximo_dia_semana(dia_atual):
 if dia_atual == 7:
  return 1
 else:
  return dia_atual + 1

for y in range(1900, 2001):
 for m in range(1,13):
  if m in (4,6,9,11): # meses com 30 dias
   for d in range(1,31):
    if (d == 1 and y != 1900 and dia_semana == 7):
     total_domingo_inico_mes += 1
    dia_semana = proximo_dia_semana(dia_semana)

  elif m in (1,3,5,7,8,10,12): # meses com 31 dias
   for d in range(1,32):
    if (d == 1 and y != 1900 and dia_semana == 7):
     total_domingo_inico_mes += 1
    dia_semana = proximo_dia_semana(dia_semana)
  else: # fevereiro
   if is_leap_year(y):
    for d in range(1,30): # se o ano for bissexto fevereiro terá 29 dias
     if (d == 1 and y != 1900 and dia_semana == 7):
      total_domingo_inico_mes += 1
     dia_semana = proximo_dia_semana(dia_semana)
   else:
    for d in range(1,29): # se o ano não for bissexto fevereiro terá 28 dias
     if (d == 1 and y != 1900 and dia_semana == 7):
      total_domingo_inico_mes += 1
     dia_semana = proximo_dia_semana(dia_semana)

print(total_domingo_inico_mes)

Primeiramente criei uma função que retorna True se o ano for bissexto e False se não for.
Depois eu criei a função que calcula o próximo dia da semana (se o dia for 7 o próximo tem que ser 1, pois a semana começa novamente). Eu considerei que segunda-feira foi o dia 1, pois no enunciado do problema fala que 01/01/1900 foi uma segunda-feira e é a partir dessa data que o programa inicia.
Depois disse fiz vários "for's" que passam pelos anos, meses e dias do período especificado.
O script começa a contar a partir de 01/01/1900, mas só pode considerar na soma de domingos no início do mês a partir de 01/01/1901.

Algumas outras soluções que encontrei no fórum:

Usuário: emandres
import datetime
count = 0
for y in range(1901,2001):
    for m in range(1,13):
        if datetime.datetime(y,m,1).weekday() == 6:
            count += 1
print count

Usuário: nmadnani
numdays ={1:31,2:28,3:31,4:30,5:31,6:30,7:31,8:31,9:30,10:31,11:30,12:31}
startday = 2
count = 0
for m in range(1,13):
    currday = startday
    for curryear in xrange(1901,2001):
        leap = False
        prevyear = curryear-1
        if prevyear % 100 == 0 and prevyear % 400 == 0:
            leap = True
        elif prevyear % 4 == 0:
            leap = True

        if leap:
            currday = (currday + 2) % 7
        else:
            currday = (currday + 1) % 7

        if currday == 0:
            count += 1
    tmp = numdays[m] + 1
    startday = (startday + (tmp - ((tmp/7)*7)) - 1) % 7
 
print count

Nenhum comentário:

Postar um comentário