A brute-force algoritmusok programozásának módszerei

Az első megbízás fő ötletei: PERIOD, RECURRENCE, JELLEGHETŐ JELÖLÉS. Ezeket a fogalmakat az egyes programozók jól ismerik. Ezenkívül a számozási feladatok az összes informatikai iskolai olimpia jelentős részét képezik.


1. A kombinatorikus objektumok generálása és fésülése

Számos alkalmazott probléma esetén az optimális megoldás megtalálása egy nagyon nagy (de véges!) Változat között. Néha egyszerre lehet megoldani ezt a megoldást, de a legtöbb esetben az egyetlen módja annak, hogy megtalálja az összes lehetséges lehetőséget, és hasonlítsa össze egymással. Ezért nagyon fontos számunkra, hogy megtanuljuk, hogyan építsünk algoritmust a különböző kombinátoros objektumok - SZIVATTYÚK, PERUTTÁCIÓK, ALTALAPOK stb.

A felsorolás sémája mindig ugyanaz lesz:

    - Először is meg kell állapítanunk az RENDELKEZÉSET az átadandó tételekre (különösen annak meghatározására, hogy melyik lesz az első és az utolsó);

- másrészt, hogy megtanuljuk, hogyan mozogjunk egy tetszőleges elemről a mögötte lévő másikra (vagyis egy adott x1 elemre, készítsünk egy x2 elemet úgy, hogy x1

Az összetett tárgyak megrendelésének legtermészetesebb módja a szótárban elfogadott LEXIKÓGIAI rend (először a szavak első betűit hasonlítják össze, majd a másodikikat stb.) - ez az, amit leggyakrabban használunk. De a következő elem megszerzésének eljárása minden alkalommal meg kell újulnia. Eddig a nyilvántartási sémát írjuk le ebben a formában:

ahol az első az első elem; Utolsó az utolsó elem; Ezután a következő elem beszerzésének módja.

1.1. szekvenciák

Az N hosszúságú sorozatok nyomtatása az 1,2-es számokból. M.

Első = (1,1,1) Utolsó = (M, M. M)

Összességében ezek a szekvenciák M ^ N (bizonyíték!). Megérteni. A következő eljárás működése, kezdjük el a példákat. Legyen N = 4, M = 3. majd:

Következő (1,1,1,1) -> (1,1,1,2) Következő (1,1,1,3) -> (1,1,2,1) Következő (3,1,3, 3) -> (3,2,1,1)

Most írhatja az általános eljárást Következő:

Ha ilyen nem található meg, akkor a következő sorrend nem létezik - elértük az utolsóat (M, M. M). Felhívjuk a figyelmet arra is, hogy ha a szekvencia számai nem 1-től M-ig, hanem 0-tól M-1-ig terjednek, akkor a következő lépése azt jelenti, hogy 1-et kell hozzáadni az M-ary számrendszerhez. A Pascal teljes programja így néz ki:

1.2. permutációk

Nyomtassa ki az 1.N számok összes permutációját (vagyis az N hosszúságú szekvenciákat, amelyekbe az 1.N számok mindegyike pontosan egyszer lép be).

Először = (1,2 N) Utolsó = (N, N-1. 1)

Összességében ezek a permutációk N! = N * (N-1) *. * 2 * 1 (igazolja!). Az algoritmus összeállítása Következő kérdezzük meg magunknak: melyik esetben lehet az i-edik permutációs tag megnövelni az előző módosítását? Válasz: ha kevesebb, mint bármelyik alábbi tag (az i-nél nagyobb számmal rendelkező tagok).

Meg kell találnunk a legnagyobb i-t, amelyre ez így van. ilyen, hogy X [.> X [N] (ha nincs ilyen i, akkor a permutáció az utolsó). Ezután X [i] -ot meg kell növelni a lehető legkisebb mértékben, azaz. megtalálható az X [i + 1] között. X [N] a legkisebb a nagyobb szám. Ha X [i] -ot megváltoztatjuk, akkor továbbra is az i + 1 számmal rendelkező számokat kell rendezni. N úgy, hogy a permutáció a legkisebb, azaz növekvő sorrendben. Ezt megkönnyíti az a tény, hogy már elrendezve vannak csökkenő sorrendben:

Most írhatja a programot:

Soroljon be egy egész pozitív N számla partícióit pozitív egész számokká (a kifejezések sorrendjében különböző partíciók egynek tekintendők).

Példa: N = 4, particionálás: 1 + 1 + 1 + 1, 2 + 1 + 1, 2 + 2, 3 + 1, 4.

Első = (1,1,1) - N egységek Utolsó = (N)

Annak érdekében, hogy a partíciók ne legyenek megismételve, beleegyezünk abba, hogy a nem növekvő sorrendben felsoroljuk a feltételeket. Annak elmondása, hogy hányan lesz minden, nem könnyű (lásd a következő pontot). Az algoritmus összeállítása Ezt követően kérdezzük fel ugyanazt a kérdést: mely esetben lehet a partíció i-edik idejét megnövelni a korábbiak megváltoztatása nélkül?

Először is X [i-1]> X [i] vagy i = 1. Másodszor, nem lehetek az utolsó elem (az i növekedést kompenzálni kell a következő csökkenésével). Ha nincs ilyen i, akkor ez a partíció az utolsó. Az i növelésével az alábbi elemeket minimálisan kell figyelembe venni, azaz egyenlő:

L-vel jelöljük a jelenlegi partícióban szereplő kifejezések számát (egyértelmű, hogy 1.)<=L<=N). Программа будет выглядеть так:

1.4. Számlálási mennyiségek

Néha megtalálja az objektumok számát ezzel vagy az adott tulajdonsággal, és nem felsorolja azokat. Egy klasszikus példa: C (n, k) - az n-elemkészlet összes k-elem-alcsoportjának száma - a C függvény táblázata kitöltésével a következő képletekkel tölthető ki:

(N-1, k) = C (n-1, k-1) + C (n-1, k) = C (n, n) = 1 1, 0

vagy az n! / (k! * (n-k)!) képlet segítségével (az első mód hatékonyabb, ha sok C (n, k) értéket kell kiszámítani).

Próbáljuk kiszámítani a partíciók számát az 1.3. Pontból. Jelöljük r (n, k) (ha n> = 0, k> = 0), a szám Nij razbie- N szempontjából a pozitív egész számok, amelyek nem haladják meg a k (ahol R (0, k) van beállítva egyenlő 1 minden k> = 0). Nyilvánvaló, hogy az R (N, N) szám a kívánt szám. Az N összes partícióját a maximális értéktől függően a csoportoknál nem meghaladó kifejezésekre osztjuk (ezt i-val jelöljük).

Az R (N, k) szám megegyezik a k partíciók számának összegével (az összes i-ből 1-től k-ig), és a maximálisan megegyező i értékkel. Az N partíciója legfeljebb k-ra az első summával egyenlő i-vel lényegében az n-i partíciói olyan kifejezésekre, amelyek nem haladják meg az i értéket (i<=k). Так что

A többiek a házi feladatban fogják elvégezni magukat.

A játék "Hanoi torony" a következő. Három mag van. Az első közülük N gyűrű piramisát viseli (nagy, alacsonyabb felülről). A gyűrűket egy másik rúdhoz kell mozgatni. Lehetőség van arra, hogy a gyűrűket a rudakról a rúdra cserélje, de a kisebbre nem helyezhet nagyobb gyűrűt. Hozzon létre egy programot, amely jelzi a szükséges műveleteket.

H Rekurzív eljárást írtunk az M-felső gyűrűk A-rúdról a B-re történő mozgatására azzal a feltételezéssel, hogy a többi gyűrű nagyobb méretű és a rudakon mozgás nélkül fekszik:

Először át a piramis M-1 gyűrűket a harmadik rúd C. Ezután M-edik gyűrű elengedése, és átvihető a B. Meg kell mozgatni a piramis N-1 és C-gyűrű B. A kezdeti feladat könnyebb? Az a tény, hogy a gyűrűk száma kevesebb lett. Most a főprogram több sorban írható:

Ha ismeri a számítógépes grafika alapjait, akkor megpróbálhat "felhívni" a képernyő minden egyes lépését.

Így bármely rekurzív megoldás alapötlete, hogy a probléma pontosan ugyanolyan, de a paraméter alacsonyabb értékével csökken. Ebben az esetben a paraméter bármely minimális értéke (például 1 vagy 0) rekurzív hívás nélkül megoldást kell adnia - máskülönben a program "ciklusokban" fog menni (a rekurzív hívások sorozata végtelen). Ez a matematikai indukció módszerére emlékeztet. Bizonyos problémák esetén célszerű a fordított, növelni egy paraméter értékét egy rekurzív hívásban. Ezután természetesen egy "rekurzív" megoldást kell biztosítani a paraméter maximális értékére. Próbáljuk meg használni ezt az ötletet kombinációs objektumok kereséséhez.


2.3. Szekvenciák (rekurzív algoritmus)

A feladat ugyanaz, mint az 1.1. Ismertetjük a rekurzív eljárást Generate (k), amely az N hossza összes olyan sorozatot mutatja, amely az X. [X], X [2] kezdetét rögzíti. X [k]. Nyilvánvaló, hogy k = N esetén triviális megoldásunk van: csak egy ilyen szekvencia van - maga is. K számára

A fő program most nagyon egyszerűnek tűnik:


2.4. Permutációk (rekurzív algoritmus)

A feladat ugyanaz, mint az 1.2. Bekezdésben. Leírjuk a (k) létrehozó rekurzív eljárást, amely bemutatja az 1. N számok összes permutációját, amelyekre az X [1], X [2] kezdetét rögzítettük. X [k]. Miután kilépett az eljárásból, az X tömb értéke megegyezik a belépés előtt (ez lényeges!). Nyilvánvaló, hogy k = N esetében újra csak a triviális megoldás van - maga a permutáció. K számára

Fő program:


3. Mellkas visszavonulással

Ahogy már megértettük, a kombinatorikus objektumok kombinálása rendkívül nehéz feladat még egy számítógép számára is. Például a nyolc számmal rendelkező permutáció 8 lesz! = 40320 - a szám meglehetősen nagy. Ezért minden felsorolt ​​feladatban a fő cél a PERES számának csökkentése, Azon tárgyak kizárásával, amelyek nyilvánvalóan nem lehetnek megoldásai a problémára. Tegyük fel, hogy csak azokat a permutációkat kell figyelembe venni, amelyekre az összeg | X [i] -i | egyenlő 8. Nyilvánvaló, hogy sokkal kevesebb lesz: például minden permutáció 8,7-kor kezdődik. nem kell figyelembe venni! Hogyan módosíthatjuk a keresési algoritmusunkat ebben az esetben? Ha valamilyen szinten az összeg

már nagyobb, mint 8, akkor vegye figyelembe az összes permutációt, ami X-vel kezdődik [1]. X [k] nincs többé szükségünk - vissza kell térnünk az X [k] -be, és meg kell változtatnunk annak értékét ("vissza kell menni" - tehát a módszer neve).

Egy ilyen helyzetben egy közös módszert fogunk figyelembe venni, amely szinte mindig lehetővé teszi a mellszobor jelentős mértékű csökkentését. Hagyja, hogy a kívánt megoldás legyen a forma szekvenciái között

ahol mindegyik X [i] az A [i] variánsok sorozatából van kiválasztva. Tegyük fel, hogy már létrehoztuk az X sorozatot [1]. X [k] (k

Azt is feltételezzük, hogy van néhány egyszerű módszer, P (X [1] X [k].), Amely lehetővé teszi számunkra, hogy válaszoljon a kérdésre: lehetséges, hogy továbbra is az X [1]. X [k] a döntés előtt (igaz) vagy sem (hamis). Megjegyezzük, hogy a valódi érték még mindig nem garantált jog ilyen kiterjesztés, de ez hamis garantált noncontinuability ( „nem érdemes tovább, és próbálja”). Egyszerű rekurzív eljárást kapunk a HULLADÉKVESZÉLYRE VONATKOZÓAN:

Ennek a módszernek egy példája a 8 queen-es probléma.