View Full Version : [Vari] Contest 13: Date
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
!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:
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!
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
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).
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
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...
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
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
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();
}
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:
Anche a me salta fuori 811.
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();
}
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)
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
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
Mannaggia, se passa qualcuno a correggere in Contest 13...
Chiedete e vi sarà dato :D
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:.
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
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
■
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
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
■
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
■
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
■
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:
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.