PDA

View Full Version : [Vari] Contest 13: Date


gugoXX
11-05-2009, 19:38
Quanti lunedi' ci sono in tutti i Febbraio tra gli anni il 1900 e il 2100 compresi?

Occhio ai bisestili, che sono tutti gli anni divisibili per 4.
Ma non quelli che terminano per 00
Ma se invece il numero che termina per 00 e' divisibile per 400, allora e' di nuovo bisestile (Come il 2000).

!k-0t1c!
11-05-2009, 19:56
811

Segue il codice usato per la soluzione:

#light
open System

let countMondays year = [1..DateTime.DaysInMonth(year,2)] |> Seq.filter(fun d -> DateTime(year, 2, d).DayOfWeek = DayOfWeek.Monday) |> Seq.length
[1900..2100] |> Seq.map(countMondays) |> Seq.fold(+) 0

gugoXX
11-05-2009, 20:07
cut

!k-0t1c!
11-05-2009, 20:20
puoi spiegarmi quel "cut"?
Se ho sbagliato a postare pubblicamente la soluzione chiedo scusa e spero di aver fatto ammenda in tempo utile, diversamente dimmelo e ripristinerò il post sopra.

Vincenzo1968
11-05-2009, 20:47
C'è già un contest 12:

Contest 12 (http://www.hwupgrade.it/forum/showthread.php?t=1890800)

Se è un questione di superstizione, puoi fare come D'Annunzio:

Tratto da "1912 + 1" di Leonardo Sciascia:


Non so se per tutto l'anno 1913: ma almeno una volta,
dedicando un suo libro, D'Annunzio scrisse "1912 + 1":
per superstizione sua o della persona cui lo dedicava
o di entrambi.
...


:bimbo:

shinya
11-05-2009, 23:04
Soluzione quick'n'dirty in factor...non è proprio il massimo dell'eleganza, ma stasera sono pigro...

USING: math math.ranges make sequences kernel calendar fry locals
prettyprint ;
IN: contest12

:: get-timestamps ( year -- seq )
year 2 1 <date> days-in-month
[ [ 1+ year 2 pick <date> , drop ] each ] { } make ;

: how-many-mondays? ( seq -- n )
[ day-of-week day-name "Monday" = ] filter length ;

: contest12 ( -- )
1900 2100 [a,b]
[ get-timestamps how-many-mondays? ] map sum . ;


@!k-0t1c!: cos'è? F#? Fico!

ndakota
11-05-2009, 23:39
Soluzione quick'n'dirty in factor...non è proprio il massimo dell'eleganza, ma stasera sono pigro...

USING: math math.ranges make sequences kernel calendar fry locals
prettyprint ;
IN: contest12

:: get-timestamps ( year -- seq )
year 2 1 <date> days-in-month
[ [ 1+ year 2 pick <date> , drop ] each ] { } make ;

: how-many-mondays? ( seq -- n )
[ day-of-week day-name "Monday" = ] filter length ;

: contest12 ( -- )
1900 2100 [a,b]
[ get-timestamps how-many-mondays? ] map sum . ;


@!k-0t1c!: cos'è? F#? Fico!

si F#, quoto! :p

pierosa
12-05-2009, 00:02
Aggiungo una soluzione in ruby

require 'date'
def is_leap?(year)
((year % 4 == 0) && ((year % 400 == 0) || !(year % 100 == 0)))
end

def mondays(start_y, end_y)
mondays = (end_y-start_y+1)*4
start_y.step(end_y){|year| mondays += 1 if (is_leap?(year) && Date.new(year,2,1).wday == 1)}
mondays
end

puts mondays(1900, 2100)

Kralizek
12-05-2009, 00:15
811

Segue il codice usato per la soluzione:

#light

open System

let countMondays year =
let isMonday day =
let date = DateTime.Parse(sprintf "%i/02/%i" day year)
date.DayOfWeek = DayOfWeek.Monday
let febDays = if year % 4 = 0 && (year % 400 = 0 || year % 100 <> 0) then 29 else 28
[1..febDays] |> Seq.filter(isMonday) |> Seq.length

[1900..2100] |> Seq.map(countMondays) |> Seq.fold(+) 0


non potevi usare DateTime.IsLeapYear (int) dove il parametro è l'anno?

!k-0t1c!
12-05-2009, 00:26
@!k-0t1c!: cos'è? F#? Fico!
Sì, F# :)
Non è niente male, corre veloce quanto C# e si integra alla perfezione con .NET ;) Comunque a giudicare dalla tua soluzione non sono l'unico che apprezza linguaggi quantomeno un po' "esotici" :p
non potevi usare DateTime.IsLeapYear (int) dove il parametro è l'anno?
No, perché DateTime.IsLeapYear avrebbe ritornato true per 1900 e 2100 mentre nella definizione di bisestile data dal problema solo per nessuno di quei due andava considerato tale (lo so, ai fini della soluzione è irrilevante visto che ciascuno ha comunque 4 lunedì in febbraio, tuttavia per scrupolo ho preferito implementare la specifica).

shinya
12-05-2009, 00:35
Comunque a giudicare dalla tua soluzione non sono l'unico che apprezza linguaggi quantomeno un po' "esotici" :p
E' Factor :) E' un linguaggio concatenativo. Fai conto lisp... ma al contrario e senza parentesi :P

gugoXX
12-05-2009, 00:46
puoi spiegarmi quel "cut"?
Se ho sbagliato a postare pubblicamente la soluzione chiedo scusa e spero di aver fatto ammenda in tempo utile, diversamente dimmelo e ripristinerò il post sopra.

Nono, ero io che avevo sbagliato. Pensavo di aver postato una errata definizione di bisestile, ma e' giusta.

C'è già un contest 12:
:bimbo:

Mannaggia, se passa qualcuno a correggere in Contest 13...

bio82
12-05-2009, 00:46
che bello un problema che riesco a risolvere anche io!!!!!!


For i = inizio To fine
If i Mod 400 = 0 Then
Dim data As Date = "01/02/" & i
If data.DayOfWeek = DayOfWeek.Monday Then
conta += 1
End If
ElseIf Right(i.ToString, 2) = "00" Then
ElseIf i Mod 4 = 0 Then
Dim data As Date = "01/02/" & i
If data.DayOfWeek = DayOfWeek.Monday Then
conta += 1
End If
End If
conta += 4
Next


come soluzione funziona, l'unico buco è l'anno 0 dove bisognerebbe fare un caso a parte :D

cmq ho paura che arrivi un inghippo per cui le nostre soluzioni diventano obsolete...

bio

gugoXX
12-05-2009, 00:52
Sì, F# :)
Non è niente male, corre veloce quanto C# e si integra alla perfezione con .NET ;) Comunque a giudicare dalla tua soluzione non sono l'unico che apprezza linguaggi quantomeno un po' "esotici" :p

No, perché DateTime.IsLeapYear avrebbe ritornato true per 1900 e 2100 mentre nella definizione di bisestile data dal problema solo per nessuno di quei due andava considerato tale (lo so, ai fini della soluzione è irrilevante visto che ciascuno ha comunque 4 lunedì in febbraio, tuttavia per scrupolo ho preferito implementare la specifica).

La specifica "dovrebbe" essere la definzione corretta di bisestile.
Se la IsLeapYear e' implementata correttamente dovrebbe tornare false per 1900 e 2100

gugoXX
12-05-2009, 01:00
Per ora in C# butto cosi'.


static void Main(string[] args)
{
var mondays = Enumerable.Range(1900, 2100 - 1900 + 1)
.Sum(year =>
Enumerable.Range(1, DateTime.DaysInMonth(year, 2))
.Count(day => new DateTime(year, 2, day).DayOfWeek == DayOfWeek.Monday)
);

Console.Write(mondays);
Console.ReadKey();
}

bio82
12-05-2009, 01:02
La specifica "dovrebbe" essere la definzione corretta di bisestile.
Se la IsLeapYear e' implementata correttamente dovrebbe tornare false per 1900 e 2100

dettomi questo, ti confermo che in vb IsLeapYear ritorna falso al 1900 (e agli altri)..

il mio codice varia in:


For i = inizio To fine
If DateTime.IsLeapYear(i) Then
Dim data As Date = "01/02/" & i
If Data.DayOfWeek = DayOfWeek.Monday Then conta += 1
End If
conta += 4
Next


risultato corretto ed uguale al codice di che postato prima :D

Per ora in C# butto cosi'.


devo dire che a complicarti la vita fai paura :D ... è più prestante immagino (tralasciando questo caso specifico)...

bio

^TiGeRShArK^
12-05-2009, 01:03
ma è giusto 811?
a me esce un pò di meno.. :stordita:

shinya
12-05-2009, 01:08
Anche a me salta fuori 811.

gugoXX
12-05-2009, 01:08
devo dire che a complicarti la vita fai paura :D ... è più prestante immagino (tralasciando questo caso specifico)...

bio

Si', e' vero, e' brutto. PRovo cosi'


static void Main(string[] args)
{
var mon = from year in Enumerable.Range(1900, 2100 - 1900 + 1)
let DaysInFeb = DateTime.DaysInMonth(year, 2)
from day in Enumerable.Range(1, DaysInFeb)
let dayday = new DateTime(year, 2, day)
where dayday.DayOfWeek == DayOfWeek.Monday
select dayday;

int nums = mon.Count();

Console.WriteLine(nums);
Console.ReadKey();

}

gugoXX
12-05-2009, 01:09
ma è giusto 811?
a me esce un pò di meno.. :stordita:

Hai incluso il 2100?

!k-0t1c!
12-05-2009, 01:09
Ouch, chiedo scusa, ho appena appreso la reale definizione di bisestile ed abbandonato la supposizione naive che fosse bisestile ogni anno divisibile per 4. Ho aggiornato la mia soluzione per sfruttare il beneficio di questa conoscenza e per essere anche 1po' meno prolissa :)

DanieleC88
12-05-2009, 01:09
811, codice in Python:
#!/usr/bin/python
# -*- coding: utf8 -*-

#
# Count mondays
#

def IsLeapYear(year):
"""Checks if year y is leap or not."""

return (year % 4 == 0) and ((year % 100 != 0) or (year % 400 == 0))

def CountMondays(monthDays, firstMonday):
"""Counts the number of mondays in the given range of days."""

d = (monthDays - firstMonday)
return (d // 7) + 1

def CountMondaysInRange(a, b, monday):
"""Count the number of mondays in the give range of years [a; b]."""

total = 0
first = monday

for year in xrange(a, b + 1):
leap = IsLeapYear(year)

first -= 1
days = 28 + int(leap)

if (first <= 0):
first += 7

total += CountMondays(days, first)
first -= int(leap)

return total


if __name__ == "__main__":
print CountMondaysInRange(1900, 2100, 5)

bio82
12-05-2009, 01:10
ma è giusto 811?
a me esce un pò di meno.. :stordita:

a me è uscito 811 al primo colpo...

praticamente sono 804 lunedì contanto gli anni e moltiplicandoli per 4, + 7 anni bisestili che hanno 5 lunedì (1904,1932,1960,1988,2016,2044,2072)..

se non sbaglio è giusto ( :mc: )

bio

pierosa
12-05-2009, 01:14
anche a me da 811


require 'date'
def is_leap?(year)
((year % 4 == 0) && ((year % 400 == 0) || !(year % 100 == 0)))
end

def mondays(start_y, end_y)
mondays = (end_y-start_y+1)*4
start_y += 4-(start_y%4) unless start_y%4==0
start_y.step(end_y,4){|year| mondays += 1 if (is_leap?(year) && Date.new(year,2,1).wday == 1)}
mondays
end

puts mondays(1900,2100)


piccola modifica

^TiGeRShArK^
12-05-2009, 01:18
Anche a me salta fuori 811.

sistemato..
nel rincoglionimento notturno avevo scritto 4 e 3 anzichè 5 e 4 :muro:

require 'Date'

def mondays_count(date)
first_monday = 1 - date.wday
if first_monday == 0 && date.leap?
return 5
end
return 4
end

date = Date::civil(1900, 2, 1)
end_date = Date::civil(2100, 3, 1)
mondays = 0
while date < end_date do
mondays += mondays_count(date)
date = date >> 12
end

puts mondays

VICIUS
12-05-2009, 01:44
Mannaggia, se passa qualcuno a correggere in Contest 13...

Chiedete e vi sarà dato :D

PGI-Bis
12-05-2009, 04:51
Java

import java.util.Calendar;

public class Main {

public static void main(String[] args) {
Calendar timer = Calendar.getInstance();
int mondays = 0;
for(timer.set(1900, 1, 0);timer.get(Calendar.YEAR) <= 2100; timer.add(Calendar.DAY_OF_MONTH, 1)) {
mondays += (Math.abs(Integer.signum(timer.get(Calendar.MONTH) - Calendar.FEBRUARY)) - 1) *
(Math.abs(Integer.signum(timer.get(Calendar.DAY_OF_WEEK) - Calendar.MONDAY)) - 1);
if(timer.get(Calendar.MONTH) == Calendar.MARCH) {
timer.set(timer.get(Calendar.YEAR) + 1, 1, 0);
}
}
System.out.println(mondays);
}
}

84ms "a freddo", 10ms "hotspotted" su un glorioso AMD 3200+, WindowsXP SP3.

Ps.: usiamo tutti i calendari ma non è che il conto, alla fine, è il risultato di una semplice equazione? A quest'ora del mattino non so la risposta :coffee:.

bio82
12-05-2009, 08:04
84ms "a freddo", 10ms "hotspotted" su un glorioso AMD 3200+, WindowsXP SP3.


ci vorrebbe vincenzo (http://www.hwupgrade.it/forum/showpost.php?p=25548955&postcount=77) a stilare la classifica..anche se non è facilissimo stavolta, anche non compilato il mio codice segna 0 ms :D facendolo da 1 a 9999 impiega già 7 millisecondi...

bio

^TiGeRShArK^
12-05-2009, 08:50
Java

import java.util.Calendar;

public class Main {

public static void main(String[] args) {
Calendar timer = Calendar.getInstance();
int mondays = 0;
for(timer.set(1900, 1, 0);timer.get(Calendar.YEAR) <= 2100; timer.add(Calendar.DAY_OF_MONTH, 1)) {
mondays += (Math.abs(Integer.signum(timer.get(Calendar.MONTH) - Calendar.FEBRUARY)) - 1) *
(Math.abs(Integer.signum(timer.get(Calendar.DAY_OF_WEEK) - Calendar.MONDAY)) - 1);
if(timer.get(Calendar.MONTH) == Calendar.MARCH) {
timer.set(timer.get(Calendar.YEAR) + 1, 1, 0);
}
}
System.out.println(mondays);
}
}

84ms "a freddo", 10ms "hotspotted" su un glorioso AMD 3200+, WindowsXP SP3.

Ps.: usiamo tutti i calendari ma non è che il conto, alla fine, è il risultato di una semplice equazione? A quest'ora del mattino non so la risposta :coffee:.

si secondo me pure basterebbe una semplice equazione...ma nel rincoglionimento notturno non mi veniva in mente...
quanto meno però mi sa che è meglio fare una sola operazione per anno anzichè una per tutti i giorni di febbraio di tutti gli anni :Prrr:
a me da 25/26 ms con ruby 1.8.6 (che fa davvero pena quanto a prestazioni) sul solito macbook pro 2.4. :p

pierosa
12-05-2009, 09:06
può essere acnhe una operazione ogni 4 anni. o forse anche meno
a me da 5ms ruby 1.9 16/18ms ruby 1.8 (athlon 3200+)

rеpne scasb
12-05-2009, 09:30

shinya
12-05-2009, 09:31
La mia versione in factor dice cosi... ma questo laptop è vecchio come il cucco...

( scratchpad ) [ contest13 ] time
811
==== RUNNING TIME

0.015625 seconds

^TiGeRShArK^
12-05-2009, 09:45
Linguaggio: Carta e penna

(2100-1900+1)*4+INT((2100-1900+1+1-2)/(4*7))=811

infatti era quello che volevo fare ieri notte ma poi il rincoglionimento ha avuto la meglio :p

pierosa
12-05-2009, 09:46
Linguaggio: Carta e penna

(2100-1900+1)*4+INT((2100-1900+1+1-2)/(4*7))=811

però mi sembra che se cambi l'intervallo degli anni non è sempre corretto, cioè non è una formula generale. o sbaglio?

rеpne scasb
12-05-2009, 09:53

pierosa
12-05-2009, 09:59
si anche io avevo notato chhe c'è un febbraio con 5 lunedì ogni 28 anni(circa) ma bisogna anche tener conto dellanno da cui si parte

rеpne scasb
12-05-2009, 10:03

pierosa
12-05-2009, 10:10
Alcune considerazione per interpretare la formula:

1) In generale in un qualsiasi Febbraio ci sono solo 4 lunedi'
2) L'unica eccezione e' un mese di Febbrario di 29 giorni (anno bisestile) con il primo lunedi' del mese che cade il primo giorno del mese.
3) Passando da un anno al succesivo, il primo lunedi' del mese cala di un 1 (MOD 7) se l'anno e' non bisestile, altrimenti cala di 2 (MOD 7).

alle prime 2 ci ero arrivato infatti ho basato l'algoritmo su questo. sull'ultima non riesco a capire come poterla sfruttare per eseguire un calcolo generico.

rеpne scasb
12-05-2009, 10:21

rеpne scasb
12-05-2009, 11:23

VICIUS
12-05-2009, 12:00
Volevo provare a scrivere qualcosa di diverso in Ruby invece mi è uscita la copia di quello di TigerShark se non per qualche differenza nello stile del codice.
require 'date'
#require 'tools'

class Date
Monday = 1
end

def get_mondays(date)
if (date.wday == Date::Monday) and date.leap?
5
else
4
end
end

def contest13(start_year, end_year)
date = Date.new(start_year, 2, 1)
count = 0

while date.year <= end_year do
count += get_mondays(date)
date = date.next_year
end
count
end

#test_functions(811, 10_000, [:contest13], 1900, 2100)
puts contest13(1900,2100)
La media dopo 10.000 esecuzioni è di 4 millisecondi per chiamata con Ruby 1.9 sul mio vecchio imac.

^TiGeRShArK^
12-05-2009, 14:44
fico... ero tanto rincoglionito ieri sera che mi era pure sfuggito date.next_year ed ho usato date << 12... :stordita: