Joulukalenteri

Suomipelit.comissa julkaistiin aikanaan joulukalenteria. Tässä kaikki luukut.

Palaa kalenteriin

2007-12-18: Porojen valinta

Porojen valinta

Tämä tehtävä on suunnattu ohjelmointia harrastaville Suomipelit.comin käyttäjille. Tehtävän ratkaisuun riittää, että tuntee jonkin ohjelmointikielen perusteet.

Joulupukin tallissa on poroja, joista osa on tottelevaisia, mutta osa on kurittomia. Tottelevaiset porot vetävät rekeä oikeaan suuntaan, mutta kurittomat jarruttavat matkantekoa. Jokaisen poron luonnetta kuvaa kokonaisluku, joka on positiivinen, jos poro on tottelevainen, ja negatiivinen, jos poro on kuriton. Kokonaisluvun suuruus kertoo, kuinka tottelevainen tai kuriton poro on. Esimerkiksi luku +9 tarkoittaa, että poro vetää innokkaasti rekeä, ja luku -2 tarkoittaa, että poro panee hieman vastaan reen kulkua.

Porot odottelevat reen lähtöä tallissa, ja vierekkäiset porot on kytketty toisiinsa. Nyt tallitontun täytyy valita reen vetäjiksi vierekkäisten porojen muodostama ketju niin, että reki kulkee mahdollisimman vauhdikkaasti. Toisin sanoen vierekkäisten porojen luonnelukujen summan täytyy olla mahdollisimman suuri.

Seuraavassa esimerkissä poroja on 10 ja niiden luonneluvut ovat:

[table]
.A|.B|.C|.D|.E|.F|.G|.H|.I|.J
.+2|.-3|.+5|.-2|.+8|.+1|.-4|.-3|.+5|.+1
[/table]

Nyt reen vetäjiksi kannattaa valita porot C - F, jolloin yhteissumma on +12. Tästä näkyy, että kun mukaan täytyy valita kaikki porot tietyltä väliltä, toisinaan parhaan tuloksen saamiseksi kannattaa hyväksyä myös kurittomia poroja.

Tehtävä: Laadi ohjelma, jolle annetaan kaikkien porojen luonneluvut, ja ohjelma selvittää, mitkä porot valitsemalla rekimatka sujuu ripeimmin.

Pystytkö tekemään ohjelman niin nopeaksi, että sen suoritusaika on alle sekunti, jos porojen määrä on miljoona? Kun olet saanut ohjelman valmiiksi, kerro siitä keskustelussa!

Keskustelua luukusta

Jaa-a. Mie en oikein välitä näistä aivopähkinöistä.

– Jarska 18.12.2007 11:00

Mä oon avannu varmaan 3 luukkua tänä vuonna suomipelitin joulukalenterista. :/ Ei oo huvittanu ja enää ei oikein pääse kiinni.

– ArZ- 18.12.2007 12:57

Noh, ainahan sinä voit sitten kesällä availla ne luukut ja pitää ihan iki oman Juhannuskalenterin!

– TZ 18.12.2007 14:24

Pitänee joku ide jostain penkoa ja kattoo mitä saa aikaan. Kiva idea (mutta tylsähkö tehtävä), toivottavasti muiltakin löytyy intoa.

– LassiP 18.12.2007 14:34

Olenko tyhmä, vai miksi en ymmärtänyt tehtävänantoa.

edit: Jaa, vetäjiä voi olla loputon määrä? Nyt taisin tajuta.

– Lord Puska 18.12.2007 15:16

poro [URL='http://www.kamaa.puttilaa.com/Poro.java ']src[/url]

Jes, ihan mukava oli vähän palautella jahvaa mieliin.

Ps. Mitään sen ihmeellisempää algoritmia en jaksanut pohtia/toteuttaa, joten jos pukin on välttämättä saatava vastaus (miljoonasta porosta) selville sekunnissa, ehdottaisin pieniä laiteuudistuksia. Muilla, joilla ei siihen löydy resursseja, suosittelen vähän pienempien porokatraiden tutkiskelua.

– LassiP 18.12.2007 17:28

Katotaas saanko tol pyyttonilla, jonka opettelun eilen alotin, jotain valmiiksi.

PS. http://xkcd.com/353/

– Tomppu 18.12.2007 17:54

Noni, ohjelma on ollut jo vähän aikaa valmis, mutta miljoonajn poron laskeminen kestää hieman... Tässä nyt jotain aikoja mitä laskeskelin.

100 poroa - 0 millisekuntia :)
1 000 poroa - n. 15 millisekuntia
10 000 poroa - n. 750 millisekutia
100 000 poroa - 35-40 sekuntia
1 000 000 poroa - 1 tunti, 52 minuuttia, 6 sekuntia, 390 millisekuntia

Miljoonaa poroa on siis lähes mahdoton saada alle sekuntiin, ainakin vielä. Ja minullahan on aika surkea kone, joten muilla voi tullakin "vähän" parempia aikoja. Laitetaas vielä pääloopin koodia tähän.

Oli ainakin yksi looppi vähemmän, kuin LassiP:llä. Ircissä tosin väittää keksineen nopeamman tavan, kuin tuo minun käyttämäni. Saa nähdä mitä siitä tulee.

E: Sitten vielä ohjelmani. Listaa poroista ei ole olemassakaan, vaan se luo sen ohjelman alussa, eikä tallenna sitä mihinkään.

– Randati 18.12.2007 19:09

Ok sainpa tehtyä tollasen perus viritelmän. Python + suht moderni kone, kohta jäämässä aika pahasti vanhanaikaiseksi (1,3GHz, Radeon 9600, 512Mt RAM-muistia)

1 000 poroa -> 0.00 s
10 000 poroa -> 0.19 s
100 000 poroa -> 0.26 s
1 000 000 poroa -> 2.64 s parhaimmillaan


Katsotaan jos tässä keksisi jotain optimointitapoja tai jotain kikkoja.

– Tomppu 18.12.2007 20:10

Nyt kyllä huijaat. Näytäs sitä sun ohjelman koodia? :)

E: miasman (#reitti kanavalta) avulla (okei, hän koodasi, muutin sen vain toiselle kielelle ;) ) sain "vähän" parannettua aikoja. Menee vähän ohi vielä L2K2:n ajoista, vaikka onkin sama prossu (Sempron 3000+) ja ilmeisesti sama algoritmi.
Miljoona on pienin luku, jolla ajaksi tulee muuta kuin 0 millisekuntia.

100 000 poroa -> 0.000 sekuntia
1 000 000 poroa -> 0.015 sekuntia
10 000 000 poroa -> 0.100-0.150 sekuntia
15 469 431 poroa -> 0.150-0.230 sekuntia
15 469 432 poroa -> Muisti loppui kesken :/

Kielenä toimi java.
Toi vähän vajaa 2 tuntia tuntuu vähän "kivalta" nyt kun tietää, että saman voi tehdä 15 millisekunnissa ;)

E2: Tässä vielä uusi ohjelmani.

– Randati 18.12.2007 20:14

Nyt kyllä huijaat. Näytäs sitä sun ohjelman koodia? :)


Ei välttämättä huijaa, omani @ 5min koodausta:
10 => 2.0952383613 e-005 s

100 => 0.000141079382994 s

1000 => 0.00126608270045 s

10000 => 0.0126859698649 s

100000 => 0.125874098524 s

1000000 => 1.26971025647 s

10M => 14.0785275782 s


PS: Python FTW :)

PPS: satunnaisruudukon luomiseen menee yli 10-kertainen aika itse laskemiseen verrattuna. (Ajat ilman ruudukon luontia.)

– L2K2 18.12.2007 20:39

Sori ylhäällä siis piti olla sekunteja eikä millisekunteja. Tein nopeasti flässin mis näkyy miten sen tein. Eli aika perus. Muoks. ohop katoin väärin, tuon tarkoitus oli olla neljän alkion levynen, ei viiden.

Randati huomaa muuten että tuo sinun luuppisi käy vielä kolme viimeistä alkiota joukkona, kaksi viimeistä alkiota joukkona ja viimeisen alkion ihan turhaan. Eihän se käytännössä vie yhtään aikaa mutta kuitenkin :P

– Tomppu 18.12.2007 20:45

Muoks. ohop katoin väärin, tuon tarkoitus oli olla neljän alkion levynen, ei viiden.P
Eihän tehtävän annossa rajattu valittavien porojen määrää, se vain sattui olemaan esimerkissä 4kpl.

– ezuli 18.12.2007 21:21




Ei se sekunti niin vaikea ole...
Koneena Sempron 3000+, Corella menisi reilusti alle.
No muutkin yritystä nyt.

EDIT:
Optimointi Psyco:lla:
10      => 0.000253663524275 s
100     => 0.00033244448666 s
1000    => 0.000440279420988 s
10000   => 0.000490844506774 s
100000  => 0.00221257170953 s
1000000 => 0.0215731328982 s
10M     => 0.177919819418 s

Nyt aletaan olla asteikolla....

– L2K2 18.12.2007 21:56

Katotaas jos huomenna kerkeis/jaksais viel miettiä tuota. L2K2 voitko paljastaa käytitkö jotain menetelmää jota täällä ei ole vielä mainittu?

– Tomppu 18.12.2007 22:48

Katotaas jos huomenna kerkeis/jaksais viel miettiä tuota. L2K2 voitko paljastaa käytitkö jotain menetelmää jota täällä ei ole vielä mainittu?


Käytin...

Ajoistakin näkee helposti sen, että aikavaativuus on O(n)-luokkaa.
Menetelmän paljastan aikaisintaan huomenna.

– L2K2 18.12.2007 23:15

Hyvin köyhällä algoritmitaustalla sain aikaan pähkäilyn jälkeen tällaisia tuloksia...aika kaukana on L2K2:n numeroista... :)
Edit: Sempron 2600+ alla ja motivaatiolista (-10,10) luodaan randonilla _ennen_ kellotusta ;)

Poroja tokassa: 1000
7 poroa valittu 0.0150001049042 sekunnissa

Poroja tokassa: 10 000
7 poroa valittu 0.0160000324249 sekunnissa

Poroja tokassa: 100 000
7 poroa valittu 0.202999830246 sekunnissa

Poroja tokassa: 1 000 000
7 poroa valittu 1.96900010109 sekunnissa

Poroja tokassa: 10 000 000
7 poroa valittu 20.5320000648 sekunnissa

Python ftw

– santtil2 18.12.2007 23:15

Offtopic: Kone: Core 2 Duo 6400 @ 2.2Ghz

Oma C++ versio tuotti seuraavaa [-10,10] skaalalla

1 miljoona(a)... 0.00252937ms
10 miljoona(a)... 0.0241472ms

– makinentoni 18.12.2007 23:38

Lue koko tämän vuoden joulukalenterikeskustelu

2003 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
2004 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
2005 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
2006 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
2007 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
2008 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24