Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointiputka: Putkaposti 26: Alkukukka

Sivun loppuun

Antti Laaksonen [16.09.2008 22:34:30]

#

Tässä on uusi putkapostitehtävä:

https://www.ohjelmointiputka.net/postit/tehtava.php?tunnus=akukka

Alkukukka on täysin toisenlainen kasvi kuin aiempi jääkukka.

Metabolix [17.09.2008 00:00:21]

#

Sorruin ratkaisemaan tehtävän pitkästä aikaa Rubylla, jolloin vastaan tuli muistin määrä: 93:n kohdalla ainakin koko RAM, 2 Gt, oli täynnä ja kone takkusi niin, etten meinannut saada ohjelmaa suljettua. Pythonille käännettynä ohjelma toimi sen verran nopeammin, että oli varaa laskea joitakin asioita useampaan kertaan. Luultavasti tähän muistinkäytön optimointiin olisi ollut jokin muukin tapa.

Tyhmästä syystä jäi kisa voittamatta. ;)

Xlfrrffä ba gllcvyyvara qlannzvfra buwryzbvaava grugäiä, engxnvfhshaxgvb ibvqnna rfvggää urycbfgv erxhefvba nihyyn.

Grez [17.09.2008 00:13:45]

#

Hassua jos muisti loppuu, kun oma softa syö noin kilotavun työmuistia.

Jos ensin käyttämäni ohjelmointikielen 32-bit kokonaisluvut olisi riittäneet, niin olisin saanut toimivan softan ekalla yrityksellä :D

Vaihdoin modernimpaan versioon (VB.Net 2008), jossa on 64-bit kokonaisluvut ja softa pyörähti 0,05 sekunnissa.

Aluksi en saanut lähetettyä vastausta kun olin laittanut kukan päivien ja eri kasvatustapojen väliin tabulaattorin ja tuo vastaanottosysteemi halusi välilyönnin.

Metabolix: Ra xrxfv bvxrnfgnna zvgääa fllgä erxhefvba xälggööa.

Jos nyt kisan "voittamisesta" puhutaan, niin mulla jäi vielä tyhmemmästä syystä voittamatta. Eli huomasin koko tehtävän vasta kun 3 oli jo lähettänyt vastauksen.

User137 [17.09.2008 01:06:01]

#

Äh, ei keksi optimointeja enää tänä iltana. Koodia on niin vähän mutta lasku kestää...

.. wn xlyyä, ynfxra nyxhyhihg gnhyhxxbba raara fhbevghfgn.

Grez [17.09.2008 01:09:35]

#

Ei itsellänikään ole kuin 45 riviä mukaan lukien (turhan hieno) alkulukujen laskurutiini, kommentit ja tyhjät rivit.

User137: Xnaanggnvfvxb ynvggnn wbgnva zhhgnxva gnhyhxxbba?

Laitinen [17.09.2008 01:39:56]

#

Eiväthän nämä nopeuskilpailuja ole ellei postien julkaisuaikaa aleta julkaisemaan Project Eulermaisesti etukäteen ;). Oma ratkaisuni Haskellilla kirjoitettuna, idea sama kuin Metabolixin, mutta Haskellissa tuon idean toteuttamiseen ja pohtimiseen menee (ainakin minulla) enemmän aikaa kuin esim. C++:lla. Riveissä sitten voittaakin ainakin VB.netin, 27 riviä ja huonosti sekä ilmavasti kirjoitettuna ;).

Klik [17.09.2008 01:52:09]

#

Itse käytin ratkaisemiseen haskellia, jota kului yhteensä 13 riviä pois lukien tyhjät rivit.

Grez [17.09.2008 01:53:44]

#

Niin, viittaisinkin tuohon Metabolixin kommenttiin kisan "voittamisesta", kun oletin että hän tarkoittaa sitä ettei ole päässyt listalle ensimmäiseksi.

jlaire [17.09.2008 08:02:00]

#

Juuh, vajaa vartti meni ratkaisemiseen tehtävänannon lukemisen aloittamisesta. Minäkin käytin Haskellia, koodia on suunnilleen 8-16 riviä laskutavasta riippuen.

Esim. Project Eulerin #77 on vähän samantapainen.

Xälgva gbqryyn lxfvaxregnvfgn erxhefvvivfgn shaxgvbgn, wbxn cnynhggnn xnvxxv revynvfrg gning fnnqn unyhggh fhzzn; rfvzrexvffä avvgä ba xbyzr: [[(7,1)],[(2,1),(5,1)],[(2,2),(3,1)]]. Ghbfgn fnn gevivnnyvfgv ynfxrgghn xnvxxvra xnfihgncbwra zääeäa.

Metabolix [17.09.2008 11:07:07]

#

Grez: Erxhefvb ba ybbtvara gncn xhingn engxnvfhn, wbaxn crehfgnan ba gvrgglwra gevivnnyvra gncnhfgra (cvghhf nyyr arywä) ghagrzvara wn zhvqra gncnhfgra wnxnzvara gäzäa crehfgrryyn cvrarzcvva batryzvva (ryv wbxb nyxhyhxh bgrgnna zhxnna, wbyybva cvghhf cvrararr, gnv fvggra fvveelgääa xäfvggryrzääa cvrarzcää nyxhyhxhn).

Liian hienoista ratkaisuista sakotetaan: Gnhyhxbva gbfvnna abvgn gälqryyvfvä ghybxfvn, xhgra shaxgvb lyyä rfvggv. Gäzäa gnxvn zhvfgvnxva xhyhv avva wäexlggäiäfgv, wn fhbevghf zlöf xrfgv zryxb cvgxääa (xlzzravä frxhagrwn). Xbfxn grugäiäffä rv xhvgraxnna gneivgn gvrgbn vgfr gnibvfgn inna inva avvqra zääeäfgä, grugäiäa ibv engxnvfgn uliva lxfvaxregnvfryyn vgrenngvbyyn, wbyybva fhbevghfnvxn ynfxrgnna zvyyvfrxhaarvffn rvxä zhvfgvnxnna xhyh xhva avzrxfv (nyxhyhxhgnhyhxxb, rqryyvfgra cvghhxfvra fhzzng, lugrrafä fvvf urycbfgv nyyr xvybgnih zngnynzzna gnfba xvryvyyä).

Seuraava haaste onkin ratkaista tämä Brainfuckilla. :)

Grez [17.09.2008 11:16:53]

#

Metabolix: Ehkä olisi pitänyt tarkentaa että tässä tapauksessa turhaa. Byvfv VZB wbxfrraxva gheunn gruqä erxhefvbshaxgvb ynfxrznna fryynvfgn, wbxn zrvyyä wb 100% inezhhqryyn ba gnhyhxbffn.

Metabolix [17.09.2008 11:44:38]

#

Grez: Wbf shaxgvb ba erxhefvvivara, fvgä ibv fhbenna xhgfhn zvyyä gnunafn cnenzrgevyyn, xha gnnf vgrengvvivfrffn engxnvfhffn gälgll vgfr uhbyrugvn, rggä gnhyhxbffn ba xnvxxv fr, zvgä cvgääxva. Rrxhefvvivaraxva shaxgvb ibv cnynhggnn neiba gnhyhxbfgn, wbf fr ba wb nvrzzva ynfxrggh.

Nvan rv xhvgraxnna byr ynvaxnna fryiää, zvgxä gvynagrrg ba gnecrra ynfxrn rghxägrra, wn gncnhxfrfgn evvcchh, zvaxä ireena vgrenngvb grxrr lyvzääeävfgä glögä fhugrrffn erxhefvbyyr gllcvyyvfrra enfxnhgrra. Reääa xreena grva grugäiäa, wbffn lyv chbyrg neibvfgn byv gheuvn, ääevgncnhxfvffn wbcn 90%. Erxhefvba nihyyn aäzä wääiäg ynfxrznggn, zhggn vgrenngvb ghyv ghbffnxva gncnhxfrffn gnecrrfrra (gheunfgn ynfxraanfgn uhbyvznggn) lxfvaxregnvfrfgv whhev ghba urycbzzna zhvfgvafäägrylafä nafvbfgn; xbxb chha fvwnna evvggv fävylggää cnev rqryyvfgä evivä (ieg. svobanppv: xnvxxv yhihg gnv inva xbyzr zhhgghwnn).

Kaikenlaisille menetelmille on omat paikkansa, ja myönnän kyllä, että tässä tapauksessa oma tapani oli huonompi, kirjoitin itsekin nyt myöhemmin tuon toisen algoritmin. Se kuitenkin oli ensimmäinen mieleen tuleva tapa (kuten aika usein tällaisissa tehtävissä).

Eiköhän tämä kysymys nyt tullut puitua aika tehokkaasti. :)

Chiman [17.09.2008 13:33:47]

#

Ensimmäisenä mieleen tullut ratkaisumenetelmä riitti: Pythonilla suoritusaika 25 s. Mukava tehtävä.

Juhko [17.09.2008 15:55:15]

#

Siis, onko 2 todella alkuluku? Sehän on ykkösen lisäksi jaollinen vain itsellään, kakkosella..

Metabolix [17.09.2008 15:56:09]

#

Tietenkin 2 on alkuluku. Onko tästä muka jotain epäselvyyttä?

Grez [17.09.2008 16:05:43]

#

Juhko kirjoitti:

Siis, onko 2 todella alkuluku? Sehän on ykkösen lisäksi jaollinen vain itsellään, kakkosella..

Millä muulla sen pitäisi mielestäsi olla jaollinen, että kelpuuttaisit sen alkuluvuksi?

Juhko [17.09.2008 16:12:07]

#

Anteeksi, ajatusvirhe. :)

User137 [18.09.2008 18:24:55]

#

funktio kirjoitti:

Juuh, vajaa vartti meni ratkaisemiseen tehtävänannon lukemisen aloittamisesta. Minäkin käytin Haskellia, koodia on suunnilleen 8-16 riviä laskutavasta riippuen.

Esim. Project Eulerin #77 on vähän samantapainen.

En periaatteesta mene rekisteröitymään ko. sivustolle yhtä ongelmaa varten.

funktio kirjoitti:

Xälgva gbqryyn lxfvaxregnvfgn erxhefvvivfgn shaxgvbgn, wbxn cnynhggnn xnvxxv revynvfrg gning fnnqn unyhggh fhzzn; rfvzrexvffä avvgä ba xbyzr: [[(7,1)],[(2,1),(5,1)],[(2,2),(3,1)]]. Ghbfgn fnn gevivnnyvfgv ynfxrgghn xnvxxvra xnfihgncbwra zääeäa.

Tuossa kommentissa on kenties jotain lähimmäs ratkaisua menevää vihjettä mutta ei ihan vielä auennut :p Miten estän rekursiota havaitsemasta tapauksen [(5,1),(2,1)] ilman että laitan kaiken muistiin ja vertaan edellisiin, pitäen samalla huolen siitä että tehokkuus säilyy. (EDIT: keksinkin jo miten...) Meinaan ettei tämä ole ihan triviaali tehtävä missään kohtaa ongelmaa. Pitää olla jonkin verran matematiikan lahjoja ennen kuin noista lukupareista edes osaa laskea ratkaisut. Ehkä vaan ajattelen turhan syvällisesti tjtn...

2a+2b+3 = 7
2b+2a+3 = 7 myös, vaikkakin molemmat ovat yhteensä vain 1 tapaus. Otappa sekin vielä huomioon laskuissa >.<

Laitinen [18.09.2008 19:26:23]

#

No riippuu siitä että miten tottunut on rekursioon. Eipähän tuossa montaa minuuttia mene jos on usein joutunut toteuttamaan esim. syvyyshakuja tai backtracking-algoritmeja.

User137 [18.09.2008 20:55:03]

#

No sanotaan että rekursio toimii nyt. Törmäsin ongelmaan jossa haetaan funktiota joka pätee näissä kaikissa:
EDIT: eikä tämäkään funktio vielä tule riittämään kun dimensioita tulee mahdollisesti useampia...

f(1,1)=2
f(2,1)=3
f(2,2)=6
f(3,2)=12
f(x,y)=???

Havainnollistaen f(2,2)
xxOO
xOOx
xOxO
OxxO
OxOx
OOxx (= 6 eri tapausta)

Metabolix [18.09.2008 21:37:47]

#

User137: Nyt en kyllä ollenkaan käsitä, mitä tuossa laskeskelet.

hunajavohveli [19.09.2008 00:02:44]

#

No voi pahus, keksin mielestäni järkevän ratkaisun melkein heti, mutta sitten minultakin loppui lukujen tarkkuus aivan loppumetreillä. Kaipa tuo 97 riittää täksi illaksi, jos vaikka huomenna jaksaisin portata pythonille ja puristaa pari viimeistä lukua irti. :) En ole muiden ratkaisuja lukenut, mutta omani on O(n2) sekä aika- että tilavaativuudeltaan, hurahtaa 800MHz:n koneella 20000 kertaa sekunnissa.

Edit: Korjaan, tilavaativuus on O(n).

Grez [21.09.2008 12:39:47]

#

User137 kirjoitti:

funktio kirjoitti:

Esim. Project Eulerin #77 on vähän samantapainen.

En periaatteesta mene rekisteröitymään ko. sivustolle yhtä ongelmaa varten.

Sieltä löytyy tällä hetkellä 208 ongelmaa, ja lisää tulee koko ajan. Eli jos tämän tyyppisten yksinkertaisten mutta silti minuutista parin tuntiin pohdintaa aiheuttavien ohjelmointipähkinöiden tekeminen kiinnostaa niin kannattaa rekisteröityä. Luulen kuitenkin että funktio oli suunnannut kommentin niille, jotka tekevät sekä näitä putkaposteja että PE:n tehtäviä.

FooBat [21.09.2008 17:47:14]

#

Taisi olla taas tehtävä johon on joku paljon yksinkertaisempi tapa kuin ensimmäisenä itseni toteuttama. Luultavasti ratkaisuidea on jotakuinkin sama kuin Funktiolla, mutta hänen triviaaliksi sanoma osa tuotti enemmän vaikeuksia. Olen varmaan unohtanut jonkun kombinatoriikan peruskikan, kun piti toteuttaa toi dynaamisella ohjelmoinnilla.

Sami [21.09.2008 18:25:22]

#

Foobat:
Oletettavasti se "triviaali" osa on a! / (a1! * a2! * ... * an!)

Ryv fvvf gncbwra zääeä, xhvaxn n xnccnyrggn nyxbvgn ibvqnna wäewrfgää, xha nyxvbgn N1 ba n1 xnccnyrggn, nyxvbgn N2 ba n2 xnccnyrggn, ... wn nyxvbgn Na ba na xnccnyrggn. Yvfäxfv nyxvbvqra Nv xrfxvaävfryyä wäewrfglxfryyä rv byr iäyvä.

Rfvzrexvxfv yhihg 2, 2, 2, 3 wn 4 ibvqnna wäewrfgää 5! / (3! * 1! * 1!) = 20 rev gninyyn.

Grez [21.09.2008 19:01:53]

#

Pakko sanoa että kylläpä te tunnutte tätä tehtävää ratkaisevan hankalasti. Siis ainakin nyt Samin ja User137:n kommenteista tulee fiilis, että asiaa lähestytään turhan monimutkaisesti.

Ei sen puoleen, itse taisin edellistä putkapostia ratkaista kohtuuttoman hankalasti. (vai puhuitteko jo muusta tehtävästä, kuin alkukukasta)

Metabolix [21.09.2008 19:13:30]

#

Ilmeisesti moni muukin menee samaan ansaan kuin minä aluksi. Onhan se aina mukava, ettei tarvitse yksin mokailla. ;) Eli kannattaa tosiaan keskittyä siihen, mitä kysytään ja mitä ei, ja tehdä ohjelma, joka laskee vain ensimmäisen näistä.

User137 [21.09.2008 19:58:39]

#

Siis kyllähän tuosta brute-force ratkaisun keksi muutamassa minuutissa mutta ongelma on kuinka optimoida sitä, tai ottaa ihan toinen ratkaisumalli.

Grez [21.09.2008 20:07:02]

#

No joo, Metabolix tuolla näköjään jo ihmetteli aikaisemminkin mitä oikein lasket. Mutta siis oletko tekemässä systeemiä, jolla saisi esim. miljoonan päivän kukan laskettua nopeasti? Noilla 2-100 päiväisillä kun brutellakaan ei mene kuin se muutama sekunnin sadasosa, niin tuntuu ettei siinä paljon tarvitse optimoida.

Chiman [21.09.2008 20:35:28]

#

Näissä Putkaposteissa olisi käyttöä samanlaiselle kommentointisysteemille kuin Project Eulerin tehtävissä, eli ratkaisemalla ongelman pääsisi viestiketjuun, jossa ratkaisijat esittelevät koodejaan.

Tässä tehtävässä en keksinyt kohtuullisella miettimisellä hyvää algoritmia, joten 25 sekunnin bruteforce sai kelvata. Käytin mm. kaavaa, jonka Sami mainitsi yllä.

Grez [21.09.2008 20:48:44]

#

Joo, se olis kyllä kiva. Tosin itsellä menee niissä threadeissa siellä project eulerissa aika hyvin yli hilseen usein se jutustelu (ainakin 200+ tehtävissä) :D Ja kateellisena tulee katseltua joidenkin ohjelmointikielten näppäriä ratkaisuja.

Laitoin mailia, laita vastaus jos kiinnostaa.

User137 [21.09.2008 20:52:46]

#

Bruteforce hidastuu eksponentiaalisesti joka kierroksella. Näytän nyt aluksi käyttämäni rekursion rottina, ei siitä ratkaisijoille paljon iloa ole kun niin hidas on:

// nyz = nyxhyhxhwra xbxbanvfzääeä, ny[] = nyxhgnhyh, znxfvzv ba xnfinghfcävivra zääeä
cebprqher GSbez1.Ynfxh(pbafg a: olgr);
ine v,a2: olgr;
ortva
  sbe v:=1 gb nyz-1 qb ortva
    a2:=a+ny[v];
    vs a2>znxfvzv gura rkvg
    ryfr vs a2=znxfvzv gura ortva
      vap(ghybf); rkvg;
    raq ryfr vs a2<znxfvzv-1 gura Ynfxh(a2);
  raq;
raq;

Tuon nopeudesta sen verran, että ensimmäiset 40 päivää se laskee kaikki yhteensä alle sekunnissa, siitä eteenpäin hidastuu 50 tienoilla niin paljon että kestää arviolta useista minuuteista lähtien ilmeisesti useisiin tunteihin.

Grez [21.09.2008 21:10:11]

#

lainaus:

Bruteforce hidastuu eksponentiaalisesti joka kierroksella

Tarkoitat kai, että sinun bruteforce-toteutuksesi.

Oma bruteforce saa laskettua 1800 asti saa laskettua ilman biginttejä jos likiarvo kelpaa ( 1,81976360087128E+304 ), jolloin menee 0,2 sekuntia. 10000 asti saisi laskettua ilman biginttejä 3 sekunnissa, mutta liukuluvusta tulee "INF" :D Veikkaan että biginttien kanssa tulee joku 6 sekuntia.

Metabolix [21.09.2008 21:31:56]

#

Mielenkiintoinen havainto: 10000:een asti laskeminen kestää (kokonaisluvuilla) 13 sekuntia, tulosten tulostaminen lisää tähän vielä 7 sekuntia. Tässä korostuu yhteenlaskun ja jakolaskun nopeusero. Kieli on Python.

Grez [21.09.2008 22:00:29]

#

Kyllähän tuo kieltämättä alkaa hidastua mitä isompiin mennään. Itsellä alkukukat 2-4000 vei aikaa 1,5 sekuntia mutta 2 - 10000 jo 14 sekuntia.

Arvionikin 6 sekunnista meni pahasti pieleen, mutta syy on tuossa, että prossu joutuu jo peruslaskutehtävissä rouskuttelemaan ihan eri tahtiin kun luvut alkavat olla luokkaa 10^1700.

Tästähän voi vaikka Metabolix tarkistaa onko hänellä sama tulos..

10000 20897802205926891712091343418113797592302566905658919418343390592485928264
64937770467908799819844673281153535696378902704034439892133413469707325010257857
54800649942071814029243286168662801830230746137734599586588869060389674473490921
99450377583667313315044682985279912986102607257713982004524737705271400119547403
35493172869218418155305450217379936186722209364108076736133693591046740425093668
80390916161029991767497403210615530796684016515843728917082722106530166359836363
07424166722838396504833237722246540961947468028048955927427093146536966067113986
67489392044960927306892883628280164560403949895588541399383879122128020720740862
14935719768874152158258033029160812753327275834635397945021108965747422745869399
74461748336856236814253515802149487259630047348958636940253298974581871957579137
56154905140622621231591096761843983425963848944030209134414936877753566831287637
20534459873102226453817340430111247527432546914748618584841844202617406172997958
36270534270440869864352324765935599663005998933801758022674116077065458130962257
72963585823939796700637935402413537132113090317413738821488895297712415872617129
81192462263180668236343722854003968061296737110238255429308354304221674694190416
54306649795538376889277948314015796755304779173709575449651412431862232023869477
75954940697048192133115604459536260256042982952361326129468899558816070373257911
46286932856601406390152305431659217136533057435840087056494712543651985751124171
56310938284836461242427519861296504562909596762781894267507050404967780405375532
04578916774434093556482649921793183712777307258925670227667644332535639966681964
30774560456276696378908870678416189402723171864342832115501138309493228221607367
337871878579062940

Antti Laaksonen [21.09.2008 22:10:54]

#

Tehokkaan ratkaisun keksimistä voi helpottaa, jos käy läpi muutaman ensimmäisen tapauksen kynällä ja paperilla ja miettii, miten seuraavan tapauksen voisi laskea kätevästi niiden avulla.

Tein huvin vuoksi omasta ohjelmastani QBasic-version. 33 MHz:n 486:lla koko tehtävän laskenta-aika on 0,05 sekuntia.

Sisuaski [21.09.2008 23:08:19]

#

Kokeilinpas nopeustestejä myös omalla koodillani ja näköjään arvojen 2-10000 laskeminen ilman tulostusta hoituu suunnilleen ajassa 1,5s 1,86GHz:n Pentium M -koneella (ja tuli sama tulos 10000:n tapaukseen kuin Grezillä).
Jos mukaan otetaan vastausten tulostaminen /dev/nulliin niin aikaa menee noin 2,25s (ja ilman devnulliin ohjausta 5,9s, mutta tämä ei varmaan kerro enää paljoa itse ohjelman tehokkuudesta).
Käytin ohjelmassa isojen lukujen hoitoon GMP-kirjaston C++-wrapperia, jonka voimin on tullut myös monet project eulerit ratkaistua.

Laitinen [21.09.2008 23:42:53]

#

Oma Haskell-toteutukseni laski alkukukat 2-10000 seuraavasti:

:!time ./alkukukka > /dev/null

real    0m5.089s
user    0m5.040s
sys     0m0.036s

Tämä ajettuna Intel(R) Xeon(R) CPU E5405 @ 2.00GHz :lla.

Grez [21.09.2008 23:56:41]

#

Oletanko oikein, että nuo teidänkin ratkaisut on periaatteesa brute force, eli nopeuserot riippuvat lähinnä kielen tehokkuudesta. Itse käyttämäni biginteger luokka ei tuntunut mitenkään erinomaiselta, eikä kielikään (nyt C#) ehkä ole se paras mahdollinen. Vai onko teillä jokin älkykäs kaava, joka laskee suoraan?

Metabolix [22.09.2008 00:08:35]

#

Luokittelet ilmeisesti minkä tahansa ratkaisun bruteforceksi, vai mikä sinusta olisi jotain muuta (edes jossain muussa tehtävässä)? :D Minusta tässä bruteforce on sellainen, joka ei osaa tallentaa mitään sopivia välituloksia vaan oikeasti käy läpi kaikki mahdolliset järjestykset alusta loppuun (mielekäs noin 40:een asti, aikavaatimus suhteessa tulokseen) tai jopa kokeilee kaikkia PPVV-jonoja ja valitsee ne, joissa määrät ovat alkulukuja (toimii kohtuullisesti ehkä 20:een asti, jos toteutetaan hyvin; aikavaatimus O(n 2n)).

Edit. Kaava? Eli muut kuin O(1)-ratkaisut ovat brute-forceja? :) Suureen osaan mahdollisista tehtävistä ei ole olemassa edes O(n)-aikaista ratkaisua, tämähän on nyt kai O(n*m), missä m on n:ää pienempien alkulukujen määrä.

Grez [22.09.2008 00:30:06]

#

Metabolix kirjoitti:

Luokittelet ilmeisesti minkä tahansa ratkaisun bruteforceksi, vai mikä sinusta olisi jotain muuta (edes jossain muussa tehtävässä)?

No yleensä ottaen lasken brute forceksi algoritmin, jolla ei ole mitään "älyä", eli joka käy vaan läpi kaikki vaihtoehdot. Muuna pidän jotain mikä käyttää mitä tahansa matemaattista mallia jolla päästään nopeampaan suoritustapaan tai muuta älykkäämpää algoritmia kuin kaikkien vaihtoehtojen läpikäyntiä.

Sanotaanko esimerkiksi että jos pitäisi laskea lottorivien määrä, niin en pidä bruteforcena käyttää kertomaa tyyliin 39! / 32! / 7!.

Jo laskettujen tulosten tallettamista/kakuttamista en pitäisi varsinaisesti eri alogritmina, vaan ainoastaan optimointina. Jokin sopiva ohjelmointikielihän voisi tehdä jopa ko. optimoinnin käyttäjän puolesta.

Chiman [22.09.2008 00:43:46]

#

Puhdas bruteforce olisi tässä tosiaan sellainen, joka kävisi kaikki mahdolliset yhdistelmät läpi ilman etukäteiskarsintaa ja laskisi niistä ehdot täyttävien määrät. Esim. 42 päivää kasvavalla kukalla yhdistelmiä tutkittaisiin 2^42 = 4398046511104 kpl.

Oma "bruteforceni" toimii siten, että se ... xbxbnn nyxhyhihvfgn fvaäafä grubxxnnyyn flillfunhyyn xnvxxv znuqbyyvfrg wbhxbg, wbvffn nyxvbvqra fhzznxfv ghyrr rgfvggl xnfihcävivra zääeä. Rev wäewrfglxfvä rv xälqä yäcv, inna wbhxba wäfravfgä ynfxrgnna lxfvaxregnvfryyn xnninyyn znuqbyyvfgra wäewrfglfgra zääeä.

Edit: Täsmennän vielä, etten oikeasti pidä algoritmiani bruteforce-kategoriaan kuuluvana, mutta se nojaa monia muita enemmän laskentatehoon.

Sisuaski [22.09.2008 01:04:17]

#

Grez kirjoitti:

Jo laskettujen tulosten tallettamista/kakuttamista en pitäisi varsinaisesti eri alogritmina, vaan ainoastaan optimointina. Jokin sopiva ohjelmointikielihän voisi tehdä jopa ko. optimoinnin käyttäjän puolesta.

Viestisi perusteella pidät lähes kaikkia dynaamisen ohjelmoinnin algoritmeja brute-forcena, mikä eroaa hyvin paljon termin normaalista käytöstä.

Wikipedia antaa termille "brute-force search" hyvinkin tiukan määritelmän, jonka mukaan suunnilleen ainoa oikeasti brute-forceksi kelpaava vastaus olisi tuo että generoidaan kaikki mahdolliset PPVV-jonot ja testataan mitkä niistä kelpaavat, mutta vaikka termiä laajennettaisiin sisältämään myös ne merkitykset joissa sitä normaalisti käytetään, ollaan vielä kaukana tehokkaista dynaamisen ohjelmoinnin algoritmeista.

Suosittelen siis että harkitset käyttämäsi terminologian muuttamista tässä asiassa mikäli toivot pystyväsi keskustelemaan näistä asioista aiheuttamatta hämmennystä kanssaihmisissä.

User137 [22.09.2008 01:14:13]

#

Chiman kirjoitti:

Oma "bruteforceni" toimii siten, että se ... xbxbnn nyxhyhihvfgn fvaäafä grubxxnnyyn flillfunhyyn xnvxxv znuqbyyvfrg wbhxbg, wbvffn nyxvbvqra fhzznxfv ghyrr rgfvggl xnfihcävivra zääeä. Rev wäewrfglxfvä rv xälqä yäcv, inna wbhxba wäfravfgä ynfxrgnna lxfvaxregnvfryyn xnninyyn znuqbyyvfgra wäewrfglfgra zääeä.

Tuo on täsmälleen se kaava mitä hain vähän ylempänä, en vaan ymmärrä miten sen laskee. Joukot mulla on kyllä tiedossa ja niiden laskemista kokeilleena se kyllä hakee kaikki 99 nopeasti. Ei vaan löydy mitään logiikkaa...

Toisekseen, tehtäväsivulla on lukenut jo useita putkaposteja sitten: "Erilaisia ratkaisuja tulee näkyville myöhemmin.". Milloinkas näitä ratkaisuja tulee? :p

Grez [22.09.2008 01:14:14]

#

Olen ilmeisesti sitten käyttäny termiä väärin.

Ehkäpä muotoilen kysymyksen (sisuaskille ja laitiselle) uudelleen:
Oletanko oikein, että nuo teidänkin ratkaisut on periaatteesa sellaisia että ne vaan muodostavat eri mahdolliset vaihtoehdot ja laskee niiden määrän (mahdollisesti välituloksia kakuttaen), eli nopeuserot riippuvat lähinnä kielen tehokkuudesta. Itse käyttämäni biginteger luokka ei tuntunut mitenkään erinomaiselta, eikä kielikään (nyt C#) ehkä ole se paras mahdollinen.

Vai onko teillä jokin älykäs kaava, joka laskee suoraan?

lainaus:

Tuo on täsmälleen se kaava mitä hain vähän ylempänä, en vaan ymmärrä miten sen laskee.

Yleisesti ottaen joukon järjestymisen voi laskea käyttäen kertomaa. Eli n!, jossa n on alkioiden määrä. Esim. 5! = 1*2*3*4*5. Tässä tulee vaan ongelmaksi se, että joukossa voi olla sama luku moneen kertaan, jolloin tässä tehtävässä siltä osin kaikkia eri järjestyksiä ei hyväksytä eri tapauksiksi. Eli joukosta täytyy vielä etsiä sellaiset osajoukot, joiden kaikki jäsenet on samoja ja jakaa tulos näiden joukkojen kertomilla.

Eli esimerkiksi jos otettaisiin yksi kukan 19 joukoista:
2 2 2 2 3 3 5

Niin tälle joukolle löytyy 7! / 4! / 2! = 105 vaihtoehtoista järjestystä.

En kuitenkaan ratkaisisi tätä tällä tavalla, koska minusta yksinkertaisempi menetelmä on nopeampi. Tuossa menee minusta turhaa aikaa sellaisen tiedon muodostamiseen, jota emme tarvitse. Voisi sanoa, että meitä kiinnostaa vain tietyn pituisen jakson muodostavien summavaihtoehtojen määrä, ei se, mitkä ne summavaihtoehdot ovat. Eli heti kun määrä on saatu laskettua, voidaan unohtaa kaikki muu.

Toki kaikenlaisessa pyörittelyssä voi olla ideaa ongelman analysoimiseksi esimerkiksi matemaattisen mallin löytämiseksi.

Laitinen [22.09.2008 02:00:16]

#

Luultavasti erot johtuvat ohjelmointikielten tehokkuuseroista tai toteutusten nyansseista. Programming language shootoutin mukaan C# olisi noin 50% Haskellia hitaampi, joka selittänee osan ongelmasta, vaikka itse olen ollut huomaavinani, että Haskell ei omissa ohjelmissani useinkaan pysty juuri tähän lähes C++-nopeuksiseen suoritukseen.

Edit. Huomioi, että ajoin oman ohjelmani tehokkaalla tietokoneella.

Sisuaski [22.09.2008 02:02:10]

#

Grez kirjoitti:

Oletanko oikein, että nuo teidänkin ratkaisut on periaatteesa sellaisia että ne vaan muodostavat eri mahdolliset vaihtoehdot ja laskee niiden määrän (mahdollisesti välituloksia kakuttaen), eli nopeuserot riippuvat lähinnä kielen tehokkuudesta. Itse käyttämäni biginteger luokka ei tuntunut mitenkään erinomaiselta, eikä kielikään (nyt C#) ehkä ole se paras mahdollinen.

Suunnilleen näin menee. Veikkaisin, että oman koodini tehokkuus suhteessa muihin johtuu pääasiassa tuon GMP-kirjaston (joka on muistaakseni osittain kirjoitettu assemblyllä) tehokkuudesta.
Ohjelmassani lähes kaikki aika vaikuttaa kuluvan pienessä silmukassa jossa suoritetaan vain isojen lukujen yhteenlaskua, eli sen nopeus on ehdottomasti dominoiva tekijä ohjelman nopeuden kannalta.

Periaatteessahan GMP:lle voisi tehdä wrapperin suunnilleen mille tahansa kielelle, eli sinänsä tässä ei ole kyse niinkään edes kielen nopeudesta vaan lähinnä saatavilla olevista kirjastoista.

Metabolix [22.09.2008 12:32:31]

#

Grez kirjoitti:

Sanotaanko esimerkiksi että jos pitäisi laskea lottorivien määrä, niin en pidä bruteforcena käyttää kertomaa tyyliin 39! / 32! / 7!.

Lähemmin tarkasteltuna tämäkin algoritmi on O(n)-aikainen, koska kertoman n! laskemiseen tarvitaan n-2 kertolaskua. Ja voisihan jokin ohjelmointikieli sisältää myös valmiin taulukon alkukukkien kasvatustavoista. ;)

Itse tosiaan käytin Pythonia. Rubylla sama algoritmi vaati puolet enemmän aikaa (eli (1+½) * t, missä t on Python-version aika; tästä puolikkaasta on usein epäselvyyttä).

Grez [22.09.2008 12:59:04]

#

Metabolix kirjoitti:

Lähemmin tarkasteltuna tämäkin algoritmi on O(n)-aikainen, koska kertoman n! laskemiseen tarvitaan n-2 kertolaskua. Ja voisihan jokin ohjelmointikieli sisältää myös valmiin taulukon alkukukkien kasvatustavoista. ;)

Niin, tuohan oli vastauksena kysymykseesi esimerkki, jota en pidä brute forcena. Itse epäilit, että pidän mitä tahansa ei O(1) ratkaisua bruteforcena. Tuo on joka tapauksessa huomattavasti fiksumpi ja nopeampi tapa kuin käydä kaikki vaihtoehdot läpi.

SirDayBat [24.09.2008 15:32:11]

#

Tulipa C-ratkaisun lisäksi tehtyä jonkinlainen Brainfuck-sähellyskin:
http://paste.dy.fi/?VAG

Tulostaa ekalle riville kahden päivän alkukukan kasvatustapojen määrän, tokalle kolmannen etc.

Ei sillä tätä tehtävää käytännössä kuitenkaan ratkasta, on (yllättäen) tosi hidas :)

kamilla [26.09.2008 17:30:31]

#

Loysinpa mielenkiintoisen sivuston, toteutin todella ruman bruteforce-version, ja nyt kommentteja lukiessa huomaan, etta parantamisen varaa on, ja paljon, aikavaatimus tuotoksessa luokkaa O(n^n^n^n^n...)taytynee ottaa 'neuvoista' jotain irti.

Grez [26.09.2008 17:41:24]

#

kamilla kirjoitti:

aikavaatimus tuotoksessa luokkaa O(n^n^n^n^n...)taytynee ottaa 'neuvoista' jotain irti.

Tuskin nyt kuitenkaan, eiköhän O(n^6) ole jo raskaudessa aika kova saavutus tähän tehtävään. Tällöin 100 päivän kukan laskemiseen menisi luokkaa 10^12 operaatiota. Tuo O(n^n^n^n^n) tarkoittaisi käytännössä että ohjelma ei saisi ikinä ratkaistua edes 4 päivän kukkaa (luokkaa 10^154 operaatiota)

kamilla [26.09.2008 17:45:26]

#

Joo, eikohan se tarkemmin ole O(n^2), taidan jo tana iltana saada aikaa version ilman tuota kakkosta, kunhan kiireiltani ehdin.

Metabolix [26.09.2008 18:00:21]

#

Ei taida ilman kakkosta olevaa versiota olla olemassa muuten kuin muodossa O(n m), vai kuinkahan tuo pitäisi kirjoittaa... Kertokaa toki, jos sellaisen keksitte.

Grez [27.09.2008 12:23:16]

#

Metabolix kirjoitti:

Ei taida ilman kakkosta olevaa versiota olla olemassa muuten kuin muodossa O(n m), vai kuinkahan tuo pitäisi kirjoittaa... Kertokaa toki, jos sellaisen keksitte.

Tekee taulukon, jossa on tieto aina edellisen kukan ja sitä seuraavan kukan kasvatusmäärien erosta ja sitten loopissa laskee pyydetyn kukan kasvatusmäärät.. :D


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta