Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointiputka: Putkaposti 21: Hyödyllinen sana

Sivun loppuun

Antti Laaksonen [10.03.2008 17:25:40]

#

Taas on putkapostin aika:

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

Ratkaisutavoista saa mielellään keskustella tässä.

Pekka Karjalainen [10.03.2008 17:39:35]

#

Ratkaisutapa 1. Selasin sanalistaa. Osui sopiva sana silmään.

Myöhemmin tapa 2, johon mietin sopivaa algoritmia.

Andu [10.03.2008 19:46:44]

#

Olenko ymmärtänyt jotakin väärin vai onko tuossa tarkistuksessa virhe?

Syötän siihen sanan "ahaa". Se vastaa, että löysi sanat "ahaa" ja "haa".
Mutta siinähän on 4 sanaa: "ahaa", "ha", "haa", "ah".

E: Kappas, niinpä näkyy :)

Antti Laaksonen [10.03.2008 19:51:02]

#

Tehtävässä on pikku sivuhuomautus:

Putkaposti 21 kirjoitti:

- - sekä lisäksi sanoissa täytyy olla ainakin kolme kirjainta.

Syynä tähän on, että lyhyemmät sanat ovat lähinnä huudahduksia ja vastaavia, joita ei ole minusta kiinnostavaa laskea mukaan.

Pekka Karjalainen [10.03.2008 20:02:52]

#

Tuossa taustalla putkahtelee tuloksia lähinnä brute forcea käyttävästä pikku ohjelmasta. Pitänee ehkä optimoida algoritmia, mutta vaarana on, että optimoinnissa menee enemmän aikaa kuin tuon nykyisen suoritukseen ;-)

Kolme eri sanaa antaa tuloksen 17 näiden tietojeni mukaan. Lisää voi olla, ehkäpä parempikin sana löytyy.

petrinm [10.03.2008 20:43:05]

#

Intelin Core 2 Duo E4500 raksutti brute forcea noin 15 min 15 sek. Hyödyntäen kylläkin vain toista ydintä. Koodi oli täysin optimoimaton.
Onneksi on kaksi ydintä niin kone ei ihan kokonaan jumitu vaan voi tehdä muutakin ajan kuluksi.

Kopeekka kirjoitti:

Kolme eri sanaa antaa tuloksen 17 näiden tietojeni mukaan. Lisää voi olla, ehkäpä parempikin sana löytyy.

Tuskin löytyy parempia kuin 17..

Pekka Karjalainen [10.03.2008 21:18:43]

#

Minulla jumittui Firefox ohjelman ajon aikana, kun muistin kulutus oli aika hurrja :)

Parempia sanoja en löytänyt, mutta 17:ään saattaa kyllä päästä useammallakin sanalla. Brute force se on joka jyllää.

Sami [11.03.2008 00:16:44]

#

Ensimmäinen toteutus noin 50 riviä ja meni 10 sekuntia, eli eipä pahemmin tarvinnut edes lähteä optimoimaan. :)

Pekka Karjalainen [11.03.2008 10:15:18]

#

Rivit jäi laskematta, kun kirjoittelin vaan jotakin tulkkiin. Linja on mennyt kehitysajan optimointiin näissä, koska malliratkaisuja ja muiden ratkojien ohjelmia ei juuri julkaista. Joskus ennen jaksoin vielä tehdä Putkaposteihin oikeita ohjelmia, jopa kommentoida koodin sekä selittää ratkaisun, ja mailata Antille. Vaan nykyään on luontainen laiskuus voittanut.

Olisihan tuo kiva nähdä esim. Samin ohjelma, niin voisi miettiä miksi se on omaa noin paljon nopeampi. Toisaalta oma meni jo hukkaan, kun suljin tulkin ja koneen :-/

Tarkoitus ei ole ahdistaa Anttia julkaisemaan asiaa vanhoista tehtävistä. Onhan tässä itse kullakin muuta tekemistä. Olisi vain kiva, jos Putkassa olisi enemmän toimintaa, jonka yhtenä seurauksena näkisi muiden huolellisesti tekemää koodia. Sellaisesta kun voi joskus vaikka oppia jotakin ...

</jaarittelu>

tkarkkainen [11.03.2008 14:09:00]

#

Kopeekka kirjoitti:

Parempia sanoja en löytänyt, mutta 17:ään saattaa kyllä päästä useammallakin sanalla.

Oman ohjelmani mukaan neljällä sanalla. Kaikilla niillä on muuten eräs yhteinen piirre.

Oma ohjelmani on bruteforce, joka kylläkin valikoi sanoja niiden pituuden perusteella. Suoritusaika on puolisen minuuttia.

Päärynämies [11.03.2008 16:40:04]

#

Voisipa itsekin koittaa tuon ratkaista jotenkin. Brute forcella raksuttamalla varmasti tuohon 17:ään toista pääsisi, mutta voisi koittaa jonkin hienomman/älykkäämmän algoritmin kehittää. Jos pääsisi huomattavasti vähemmällä kuin vain sen raa'an voiman käytön vaatimalla ajalla. Hauskempaakin niin ratkaista. Se ei paljon taitoja tai ajattelua vaadi, että osaa laatia kaikkia sanoja kaikilla muilla testaavan algoritmin. Ainoastaan aikaa voi vaatia.

Tulipa tässä mieleen sellainen ehdotus, että voisi tuolta tehtävien sivulta poistaa näkyvistä ne muiden tulokset. Laittaisi vain sijoitukset näkyville, joka sitten antaisi osviittaa siitä, mitä tasoa se oma tulos on. Niistä kun helposti löytää sen parhaan tuloksen, jolloin myös oman ratkaisun keksiminen helpottuu huomattavasti.

Sami [11.03.2008 22:23:19]

#

Kopeekka: Collections.binarySearch

Ja tajusinpahan juuri hyvinkin yksinkertaisen optimoinnin (indeksointirajojen muuttaminen siten, että se ei tutki alle 3 merkin alisanoja), joka pudotti suoritusajan 6 sekuntiin.

Päärynämies [11.03.2008 23:54:49]

#

Unohtuipa tuosta edellisestä viestistä vielä, että itsestäkin olisi mukava nähdä noita muiden ratkaisuja tuon postin päättymisen jälkeen. Tietysti ymmärrän, että mr. Ylläpitäjällä on muutakin elämää ja erinäisiä kehitysehdotuksiakin on kovin paljon tullut esille käyttäjiltä (Olisi myös kiva kuulla Antin mielipiteitä niistä ja tulevaisuudennäkymiä).

Tietysti jos ei putkaan noita saada, niin itse en näkisi myöskään huonona vaihtoehtona sellaista, että joku voisi omalle palvelintilalleen niitä sorsia varastoida näytille. Ne eivät paljoa tilaa edes vie. Itse ainakin voisin tuollaista tehdä, jos vain olisi sitä tilaa.

User137 [12.03.2008 01:34:02]

#

Kopeekka kirjoitti:

Kolme eri sanaa antaa tuloksen 17 näiden tietojeni mukaan. Lisää voi olla, ehkäpä parempikin sana löytyy.

Neljä löysi oma ohjelma noita 17 tuloksisia.

ajv [12.03.2008 08:35:06]

#

Neljähän noita löytyi tylsällä bf:llä. Sanan pituuden toimiessa karsijana suoritusaika 10 sekunnista ylöspäin. Täytyypä tutkia tuota binäärihakua...

User137 [12.03.2008 12:06:19]

#

Sekunneista puhutte? Päälle 3 minuuttia (202625ms, 3:11min) se tuota raksutteli optimoituna pituustarkistuksella ja sanalistaa lajittelematta... en pysty tuosta enää puristamaan mitään :P Kyllähän se 13 sekuntiin meni jos huijaa pituusrajan säännöttömän korkealle.

Athlon 64 Core 2 4200

ajv [12.03.2008 12:21:16]

#

User137 kirjoitti:

Kyllähän se 13 sekuntiin meni jos huijaa pituusrajan säännöttömän korkealle.

No niinpä, ilman pituustarkistusta tuo tekeleeni suoritusaika lasketaan tunneissa :)

Antti Laaksonen [12.03.2008 21:28:00]

#

Pääsyy vanhojen tehtävien ratkaisujen puuttumiseen on saamattomuuteni, mutta ratkaisujen julkaisussa on myös muutama ongelma. Ensinnäkin jos ratkaisut julkaistaan kaikkien nähtäville, moni voi katsoa suoraan ratkaisun tehtävää miettimättä. Muihinkin kuin uusimpaan putkapostiin tulee aina välillä ratkaisuja. Jos taas ratkaisut julkaistaan vain vastauksen lähettäneille, pitäisi joka tehtävässä erikseen päättää, kuinka hyvä lähetys riittää ratkaisun näkemiseen.

Alkuperäinen ajatus oli laatia tehtävistä kattavia selostuksia, ja muutama sellainen valmistuikin. Tällaisten ratkaisuiden kirjoitus on kuitenkin osoittautunut niin työlääksi, että olisi kenties parempi julkaista tulevat ratkaisut koodivinkkien tapaan, jolloin ratkaisu muodostuu koodista ja sen kuvauksesta. Tietysti samaan tehtävään voisi olla monta vaihtoehtoista ratkaisua.

Päärynämies kirjoitti:

Tulipa tässä mieleen sellainen ehdotus, että voisi tuolta tehtävien sivulta poistaa näkyvistä ne muiden tulokset.

Olen yrittänyt valita vastauksista näytettävän tiedon niin, että se paljastaa mahdollisimman vähän tehtävän ratkaisusta. On kyllä totta, että usein joku löytää parhaan ratkaisun pian tehtävän julkaisun jälkeen, jolloin tehtävän miettimisestä saattaa mennä osittain hohto. Mutta minusta muiden saamien tulosten vertailu omiin tuloksiin on yleensä sen verran hauskaa, että en haluaisi muuttaa nykyistä järjestelmää.

Kuten Kopeekka ja Päärynämies ovat arvailleet, Putkapostin toimintaa rajoittaa käytössä oleva aikani. Tärkein tavoite on, että uusia tehtäviä ilmestyy säännöllisesti, ja tämä on toteutunut melko hyvin. Muissa asioissa onkin vielä parantamista, ja toivon teiltä kärsivällisyyttä.

Korim [13.03.2008 05:16:17]

#

User137 kirjoitti:

Sekunneista puhutte? Päälle 3 minuuttia (202625ms, 3:11min) se tuota raksutteli optimoituna pituustarkistuksella ja sanalistaa lajittelematta... en pysty tuosta enää puristamaan mitään :P Kyllähän se 13 sekuntiin meni jos huijaa pituusrajan säännöttömän korkealle.

Athlon 64 Core 2 4200

Eli parannettavaa löytyy :P.

Oma ratkaisuni käy tuon listan läpi 3.5 sekunnissa (Athlon64 X2 4000+). Sen kummemmin tutkittavia sanoja valitsematta.

Sami [14.03.2008 00:50:24]

#

Ehdotin tätä Laaksoselle seuraavaksi putkapostiksi, mutta hän taas ehdotti että pistäisin sen tänne vain lisätehtäväksi, koska se on hyvin samankaltainen tämänkertaisen postin kanssa.
Eli siis tässä pieni lisätehtävä niille, jotka pitivät varsinaista postia liian helppona tai muillekin, jotka haluavat yrittää hieman vaikeutettua tehtävää:
Samaa sanalistaa käyttäen, minkä sanan kirjaimista pystyy muodostamaan eniten muita, vähintään 3 kirjaimen pituisia, suomen kielen sanoja? Esimerkiksi sanasta "maailma" saisi ainakin "maa", "ilma", "lima", "maali", "maila" ja "laama", mutta varmasti muitakin löytyy.
Jos joku tahtoo tarkistaa saamansa vastauksen, niin kyhäsin pienehkön tarkistusohjelman (java-appletti) sitä varten, joka toivottavasti toimii ja löytyy osoitteesta http://www.students.tut.fi/~maki36/OP/Tarkistaja.html. Appletti ei tosin tarkista ovatko sanat oikeita sanoja, koska sillä ei ole sanalistaa käytössä, joten se osa jää tehtävän ratkaisijan tehtäväksi.

Ja jotta kukaan ei pilaisi heti muiden iloa, niin pyytäisin ettei kukaan pistä ainakaan heti parasta sanaa esille, mutta sanamäärän tietysti voi ja on jopa suotavaakin kertoa, sekä sen kuinka helposti tehtävä ratkesi.

Antti Laaksonen [14.03.2008 18:21:00]

#

Onkos joku minun lisäkseni koettanut ratkaista Samin tehtävää? Pienen mietinnän jälkeen sain aikaan kohtuullisen nopean hakuohjelman, joka löysi eniten anagrammeja sisältävän sanan alle viidessä minuutissa. Tuolla tavalla sanan sisälle saakin mahtumaan huomattavasti suuremman joukon muita sanoja.

Metabolix [14.03.2008 19:29:02]

#

Mahtaako tähän uuteen ongelmaan olla parempaa ratkaisua kuin n2a, missä n on sanojen määrä ja a aakkoston koko?

FooBat [14.03.2008 20:47:55]

#

Putkapostin vastauksen etsimiseen meni noin 1,2 s. Samin tehtävän vastaus (11255) löytyi noin 2 minuutissa. Ajat pystyisi puolittamaan dual core prossulla, jos jaksaisi pistää tuohon toisen threadin pyörimään. Mulla oli molempiin tehtävään aika paljon valmista koodia entuudestaan, joten noihin ei mennyt kuin 20-30 riviä javakoodia kumpaankin.

Metabolix [15.03.2008 15:29:21]

#

Jaksoinpa tehdä tuon lisätehtävän, algoritmi on tosiaan pohjimmiltaan n2a. Niin kutsutulla OMG-optimoinnilla saa tässä syötteessä sijoitettua a:n paikalle pieniä numeroita (32-bittisellä koneella nelosen, 64-bittisellä tietenkin kakkosen, SSE2:n avulla kai jopa ykkösen), kun tiedetään, että mikään kirjain ei esiinny yhdessä sanassa yli seitsemää kertaa. Ohjelmani löysi sanan ajassa 13 min 37 s vanhalla 333 megahertsisellä tietokoneella, uudempi kone pääsee lähes puoleentoista minuuttiin.

Antti Laaksonen [15.03.2008 16:46:14]

#

Metabolix kirjoitti:

Niin kutsutulla OMG-optimoinnilla saa tässä syötteessä sijoitettua a:n paikalle pieniä numeroita - -

Mitä tämä optimointitapa tarkoittaa (yleensä ja tässä tapauksessa)?

Metabolix [15.03.2008 17:24:01]

#

OMG-optimointi viittaa toisinaan kaikenlaisiin merkillisiin temppuihin, jotka eivät kuulu selkeään ja hyvään ohjelmointitapaan mutta mahdollisesti nopeuttavat ohjelmaa marginaalisesti.

Tehtävän kannalta olennaista on tietää, onko tietyssä sanassa tiettyä kirjainta enemmän tai yhtä paljon kuin toisessa sanassa. Kun lasketaan jokaisen sanan eri kirjainten lukumäärät, huomataan, että suurin tulos on sopivasti seitsemän, joten määrät voi tallentaa näppärästi kolmen bitin alueisiin.

Kun kaksi n-bittisissä muuttujissa olevaa n-1-bittistä lukua vähennetään toisistaan, ylimmästä bitistä nähdään, tuliko negatiivinen tulos. Tätä voidaan soveltaa niin, että tallennetaan lasketut kolmibittiset arvot peräkkäisille neljän bitin alueille laajempaan muuttujaan. Koska olennaista ei ole laskun tulos vaan tuloksen mahdollinen etumerkki, samassa muuttujassa olevat laskut eivät häiritse toisiaan: korkeammat bitit eivät vaikuta matalampiin missään tapauksessa, matalammat taas vaikuttavat korkeampiin vain, jos tulos on negatiivinen.

Aakkostossa on kaikkiaan 29 kirjainta, joten tarvitaan 116 bittiä eli neljä 32-bittistä lukua. Tarkistus käy helposti:

bool operator >= (sana const& ylasana, sana const& alasana)
{
  for (i = 0; i < 4; ++i) {
    if ((ylasana.k[i] - alasana.k[i]) & 0x88888888) {
      // Jostain tuli negatiivinen, joten alasana ei muodostu ylasanasta
      return false;
    }
  }
  return true;
}

SSE2 mahdollistaa käsittääkseni 128-bittiset laskutoimitukset, mutta en tiedä siitä sen enempää.

Antti Laaksonen [15.03.2008 21:39:19]

#

Joo, minäkin mietin vähän tuollaisia bittivirityksiä, mutta en ole vielä toteuttanut niitä omaan ohjelmaani. Kokeilitko, miten paljon tuo nopeuttaa tavalliseen anagrammin tarkistukseen verrattuna?

Kysymys kuuluu edelleen, onko tähän ongelmaan jokin toinen tehokkaampi lähestymistapa. Voiko anagrammihakua toteuttaa aidosti nopeammin kuin vertaamalla kaikkia sanoja toisiinsa, jos sanastosta ei saa tehdä mitään oletuksia?

FooBat [16.03.2008 16:33:18]

#

On tuohon nopeampikin tapa, tosin sen koodaamiseen menee enemmän kuin tuo 2 min. Järjestetään aluksi sanat pituuden mukaan, pisimmät ensin. Sitten tutkitaan noita sanojen lukumäärää alkuperäistä listaa vastaan ja samalla kaikki osuvat sanat karsitaan tutkittavien sanojen listasta. Näin mitään sanaa mikä löytyy pidemmästä sanasta anagrammina ei tutkita uudestaan. Tämän pitäisi pudottaa suoritusajan murto-osaan alkuperäisestä.

Antti Laaksonen [16.03.2008 17:01:35]

#

Käytännössä tuo on toki hyvä optimointi, mutta pahimpaan tapaukseen se ei auta. Sanasto nimittäin voi olla sellainen, että mikään sana ei ole toisen sisällä.

Dude [16.03.2008 20:40:26]

#

Tein PHPeellä 22 rivisen viritelmän. Laitan runnaamaan 120 mhz koneella(koitin ensi lähettään nettiin mutta tuli että kestää liian kauan).
Edit: taas valittaa ajasta, pitää portata QBeelle.
Edit2: Ny tulee sanojen taulukkoon lukemises "Out of string space"

Metabolix [16.03.2008 23:26:56]

#

QB ei ole tällaisiin (DOS-mittapuulla) paljon dataa käsittäviin tehtäviin paras mahdollinen väline, ja PHP-ohjelmien ajaminen palvelimella yleensä aiheuttaa ongelmia siksi, että palvelinskriptien aikarajat ovat usein melko tiukkoja. PHP-ohjelman voi ajaa myös komentoriviltä, php jotain.php (tai php-cgi jotain.php, jolloin kylläkin tuloste sisältää HTTP-ainesta).

msdos464 [15.04.2008 20:32:49]

#

Kun kurssilla tuli (minulle) uusia tietorakenteita vastaan, niin päätin kokeilla niistä yhtä. Kieli on C, koneella (Core2Dual läppäri) kestää 2 sekuntia tunkea sanat tietorakenteeseen ja sekunti etsiä paras sana. Hörppää muistia noin 70 mt. Jos syöte olisi isompi, tuohon voisi kokeilla muutamaa optimointia vielä. Pitää kokeilla etsiä englannin kielestä vastaava lista :)

Tiedoston lukuajasta ei kyllä varmaankaan saa nipistettyä.

edit: juuh, noin 2100 ms kestää lukea ja noin 190 ms löytää paras sana. En löytänyt isompaa sanastoa, tietääkö kukaan muu? Saa olla vaikka englanniksi.

msdos464 [16.04.2008 08:53:31]

#

Aha, tietorakenteen lukemisessa olikin optimoimisen varaa.. Reallocki osoittautui hitaaksi, niin mallokoin kerralla 100000 alkiota sanoille ja oletan, ettei niitä ole enempää. :)

Tiedoston luku noin 350 ms ja parhaan sanan etsintä noin 170 ms. Koko ohjelma (freet yms.) alle 900 ms.

msdos464 [16.04.2008 21:59:24]

#

Näyttää hölmöltä kun on 3 omaa viestiä peräkkäin :P

Paras anagrammisana löytyy noin 58 sekunnissa.. oikeastaan itse sana löytyy jo alle 13 sekunnissa, mutta loppujen sanojen läpikäynti näköjään kestää. Tähän olisi helppo keksiä jotain optimointeja, mutta en voisi olla varma, että menevätkö ne heuristiikan puolelle.

reca [10.05.2008 16:23:41]

#

Ajattelin tätä ongelmaa lähteä ratkomaan, mutta
miten käytännössä ratkomisen voisi toteuttaa
PHP:llä? Taroitan sitä, kun tulee se 30s tms
aikaraja vastaan jne...

Eli voiko tällaista PHP:n avulla ratkoa?

edit: Kirjoituksen oikeellisuutta korjailtu.

Metabolix [10.05.2008 18:12:27]

#

reca kirjoitti:

Eli voiko tällaista PHP:n avulla ratkoa?

a) Voit poistaa aikarajan PHP:n asetuksista.
b) Voit ajaa php-ohjelman komentoriviltä, esimerkiksi php koodi.php.
Vastaus olisi löytynyt jo tuosta ylempääkin.

reca [10.05.2008 22:13:25]

#

Metabolix kirjoitti:

b) Voit ajaa php-ohjelman komentoriviltä,
esimerkiksi php koodi.php.

Mitä käytännössä tapahtuu kun php ajetaan komentoriviltä?
Mitä se muuttaa verrattuna normaaliin? Miten komentoriviltä
ajettu php tulostaa tietoja?

edit: Sekoilua tagien kanssa.

Heikki [10.05.2008 22:22:09]

#

reca kirjoitti:

Mitä käytännössä tapahtuu kun php ajetaan komentoriviltä?
Mitä se muuttaa verrattuna normaaliin? Miten komentoriviltä
ajettu php tulostaa tietoja?

PHP:n tuloste tulee oletuksena komentoriville. Mitään isoja eroja "normaaliin" skriptien suorittamiseen ei ole (tietenkään esim. evästeitä ei oikein voi käyttää).

Kokeilemalla selviää:

$ echo "<?php echo 'terve'; ?>" > testi.php
$ php testi.php
terve

Andu [11.05.2008 19:41:24]

#

Minäkin ratkaisin tämän PHP:llä. Itse käytin ratkaisuna Roadsend PHP-kääntäjää, jolla voi siis luoda ihan binääreitäkin.

Matso [15.05.2008 18:48:20]

#

Metabolix kirjoitti:

reca kirjoitti:

Eli voiko tällaista PHP:n avulla ratkoa?

a) Voit poistaa aikarajan PHP:n asetuksista.
b) Voit ajaa php-ohjelman komentoriviltä, esimerkiksi php koodi.php.
Vastaus olisi löytynyt jo tuosta ylempääkin.

c) Voit ratkasta ongelman alle 30 sekunnissa. Oma Java ohjelma vääntää tuota 12-13 sekkaa.

Aikarajan voi poistaa myös PHP funktiolla set_time_limit(0).

Onko muut päätyny tulokseen 18 sanaa? Mulla nimittäin toi väittää että siitä löytys 18 sanaa, ja 2 merkkiset sanat on kyl karsittu pois. Putkapostiin kun ton sanan laitto ni se kyllä laski 17.

Sami [15.05.2008 19:38:17]

#

Matso: ettet olisi laskenut samaa sanaa kahdesti? Ainakin yksi ratkaisuista nimittäin sisältää yhden lyhyemmän sanan kaksi kertaa.

Matso [21.05.2008 11:21:54]

#

Sami kirjoitti:

Matso: ettet olisi laskenut samaa sanaa kahdesti? Ainakin yksi ratkaisuista nimittäin sisältää yhden lyhyemmän sanan kaksi kertaa.

Niin on vissiin sit käynyt.


Sivun alkuun

Vastaus

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

Tietoa sivustosta