CHOO + CHOO = TRAIN

CHOO+CHOO=TRAINMost nem a híres kisvonatról van szó, hanem egy ismert kriptoaritmetikai feladványról. Ebben a feladattípusban egyszerű matematikai műveletek szerepelnek és a különböző betűk különböző számjegyeket jelölnek. Általában többféleképpen megoldhatók: intuíció, ötlet, módszeres próbálkozás, következtetés, kizárás vagy klasszikus behelyettesítés. Ha van megoldás és meg is találunk egyet, akkor a következő kérdés az, hogy van-e még, illetve összesen hány megoldás van?

Íme a feladat:

Érdemes minden megoldás során figyelembe venni a minden számjegyet 0-9-ig végigpróbáló lépések helyett legalább az alábbi öt feltételt:

  • C >= 5, hiszen CHOO olyan négyjegyű szám, aminek a kétszerese ötjegyű szám,
  • T = 1, mivel két négyjegyű szám összege 10000 < TRAIN < 20000 (ebben az esetben),
  • O >= 6, hiszen maradéknak képződnie kell, mert I és N különbözik,
  • 2 <= N < I és
  • I >= 3 és szintén a maradékképződés miatt.

Esetleg még tovább gondolkodva, felfedezhetünk egyéb összefüggéseket, illetve kizárhatunk egyéb értékeket, így jelentősen csökkenthető egy-egy Java implementáció lépésszáma.

1. megoldás

Ez adatszerkezet nélküli megoldás, így eléggé összetett feltétellel valósul meg a művelet teljesülése (megfelelő helyiértékek használatával) és a különbözőségek vizsgálata.

2. megoldás

Itt az ellenőrzési feltétel egyszerűbb, mert a különbözőség/egyediség tesztelését áthárítottam a halmazszerűen működő HashSet generikus kollekcióra, építve annak beépített képességére.

Mit gondolsz, melyik megoldás hajtódik végre gyorsabban? Miért?

Mivel a két megoldásnál a ciklusok szervezése megegyezik, így a használt adatszerkezet dönt (hiszen annak konstrukciós és szelekciós, azaz karbantartási műveletei vannak). Az 1. megoldás a gyorsabb, mert nem használ adatszerkezetet. A 2. megoldás lényegesen lassabban fut, mert a generikus kollekció műveletei miatt az automatikus szemétgyűjtő tevékenység erősen igénybe vett. A különbség nagyságrendileg 15-szörös.

A feladatnak két megoldása van: 5466 + 5466 = 10932 és 5488 + 5488 = 10976.

A bejegyzéshez tartozó teljes – időméréssel kiegészített – forráskódot ILIAS e-learning tananyagban tesszük elérhetővé tanfolyamaink résztvevői számára.

Akinek kedve támadt, lásson hozzá hasonló feladatokhoz:

A feladat a Java SE szoftverfejlesztő tanfolyam szakmai moduljának 9-12. óra: Metódusok, rekurzió alkalomhoz, illetve a 21-24. óra: Objektumorientált programozás, 2. rész alkalomhoz kötődik.


Ajánljuk a Java SE szoftverfejlesztő tanfolyam kategóriából

“CHOO + CHOO = TRAIN” bejegyzéshez 13 hozzászólás

  1. Íme néhány nehezebb példa a kihívást keresőknek. Ezeket már másképpen érdemes/hatékony megoldani:

    • AN + ACCELERATING + INFERENTIAL + ENGINEERING + TALE + ELITE + GRANT + FEE + ET + CETERA = ARTIFICIAL + INTELLIGENCE
    • NIIHAU ± KAUAI ± OAHU ± MOLOKAI ± LANAI ± MAUI ± HAWAII = 0
    • PI * R * R = AREA
    • NORTH / SOUTH = EAST / WEST

    Nem csak egy konkrét példa megoldásának szintjén lehet gondolkodni, így aki még kitartóbb általánosabban is lehet: keresse meg az összes n1 + ... + nt = n'1 + ... + n't' alakú egyenletet úgy, hogy angolul mind matematikailag, mind pedig alfametikailag igazak legyenek, ha minden változó 20-nál kisebb különböző pozitív egész. Például:

    • TWELVE + NINE + TWO = ELEVEN + SEVEN + FIVE

    Forrás: D. E. Knuth: A számítógép-programozás művészete, 4. kötet, 2. rész, Permutációk és n-esek előállítása, AnTonCom Infokommunikációs Kft., Budapest, 2008, ISBN 987-963-87947-1-0

    Válasz
  2. Úgy érzem, hogy megértettem a rekurziót az ILIAS-os példák alapján és próbálkoztam ezzel a feladattal. Tehát íme a CHOO + CHOO = TRAIN rekurzívan:

    Válasz
    • Látszik, hogy alaposan átgondoltad és megértetted a rekurziót Anett. A szöveg jelenti az emlékezetet a programodban. A karakterek számmá átalakításához a karakterkódok különbségeit használtad. Én is továbbgondoltam a megoldásodat és kicseréltem ezt csomagolóosztály konvertáló függvényére úgy, hogy a számjegyeket ; választja el egymástól:

      Nem mértem, hogy melyikünk megoldása hatékonyabb, csak egy alternatívát szerettem volna mutatni. A rekurzió általában mindig lassabban működik az iterációhoz képest. Persze a használt adatszerkezet karbantartó műveleteinek igényeire is tekintettel kell lenni. Örülök, hogy inspirált a feladat.

      Válasz
      • Gratulálok Anett, hogy már itt tartasz. Én ezeket még nem ugrottam meg, de már kitaláltam, hogy a két alábbi c miért egyezik meg:

        c=s.charAt(0)-'0';

        c=Integer.parseInt(s.split(";")[1]);

        😉

        Válasz
      • Köszönöm Sándor. Kipróbáltam az ILIAS-ban lévő Unit tesztes időmérő tesztkörnyezettel és ezeket kaptam:
        1. megoldás végrehajtási ideje: 9 ms
        2. megoldás végrehajtási ideje: 129 ms
        3. megoldás végrehajtási ideje: 395 ms
        4. megoldás végrehajtási ideje: 2361 ms
        Szóval a rekurzió fejben nagyon szép, de a gyakorlatban nem annyira.

        Válasz

Szólj hozzá!