prohledávání do šířky a do hloubky - ih.cas.cz · 2. krok 3. krok 4. krok 5. krok 6. krok 7....
TRANSCRIPT
Úkol • postupně systematicky prohledat vymezený stavový prostor
Stavový prostor (SP) • možné stavy a varianty vývoje nějakého procesu (výpočetního, výrobního, herního...)
• co může být stavovým prostorem?
· varianty vývoje na šachovnici (hledáme cestu k vítězství)
· bludiště (hledáme cestu ven)
· silniční síť (hledáme cestu z A do B) ... a mnoho dalších příkladů
Co můžeme hledat? • nejrychlejší řešení (nejdříve dostupné)
• optimální řešení
• všechna řešení
• alespoň jedno řešení (jakékoliv)
Prohledávání do hloubky nebo do šířky • oba algoritmy vedou k úplnému prohledání SP, liší se ale pořadím navštívených míst
• v praxi mezi nimi volíme podle cíle, kterého má být dosaženo (viz dále)
Jan Hnilica Počítačové modelování 15 2
Prohledávací algoritmy
• SP si můžeme představit jako strom (a také se tak v programu často realizuje)
• kořen stromu = úvodní stav
· např. výchozí poloha v bludišti
• synové uzlu U = stavy, do kterých se lze dostat z U pomocí nějakého elementárního kroku
· elementární krok = např. postup v bludišti na další rozcestí
• listy = konec cesty
· východ z bludiště nebo slepá ulička
Jan Hnilica Počítačové modelování 15 3
Stavový prostor jako strom
A
E
B D
I J F
K H C G
I
D A B
F
L J E
C
G H
K L
Jan Hnilica Počítačové modelování 15 4
Průchod stromem do hloubky a do šířky
• cílem je postupně prohledat všechny uzly stromu • k dočasnému skladování uzlů použijeme datovou strukturu DS (viz dále) • algoritmus:
1. vlož do DS kořen stromu 2. cyklus: dokud DS není prázdná 2a. vyjmi z DS uzel U // uzel U je navštívený 2b. vlož do DS všechny syny uzlu U // např. zprava doleva
použitá datová struktura DS je:
• zásobník ⇒ průchod do hloubky uzly navštíveny v pořadí: A, B, D, E, C, F, G
• fronta ⇒ průchod do šířky (po vrstvách) uzly navštíveny v pořadí: A, B, C, D, E, F, G
A
D
B
E
C
F G
• = backtracking, DFS (depth first search)
Algoritmus • postupně prohledáváme jednu větev po druhé, postupujeme do hloubky směrem k listům
• pokud na dané cestě nenajdeme řešení, vracíme se zpět na místo předchozího větvení a vydáme se jinou cestou
Realizace • rekurzivní funkce nebo cyklus s vlastním zásobníkem
Paměťová složitost • odpovídá výšce stromu (na zásobníku udržujeme pouze aktuálně prohledávanou cestu)
• ⇒ obvykle dobře zvládnutelné
Časová složitost • odpovídá počtu uzlů ve stromu, které musíme navštívit
• ⇒ exponenciálně roste s výškou stromu
• ⇒ časově extrémně náročné, použitelné pro malé úlohy
Jan Hnilica Počítačové modelování 15 5
Prohledávání do hloubky
• pro zmírnění časových nároků se používají prořezávání a heuristiky
Prořezávání • při každém kroku hlouběji k listům zkoušíme průběžně vyhodnotit, jestli daná cesta
může vést k nalezení řešení
• pokud můžeme určit, že cesta vede do slepé uličky, ihned se vracíme a neztrácíme čas jejím rozvíjením („odřízneme“ celý podstrom)
• ne vždy je prořezávání možné, ale pokud ano, dokáže zásadním způsobem snížit časové nároky algoritmu
Heuristiky • použitelné, pokud hledáme jedno řešení (jakékoliv)
• princip: přednostně procházíme ty větve, kde tušíme existenci blízkého řešení
• heuristika = intuitivní odhad, jakou cestou se vydat (kde by se řešení mohlo nalézat)
• dobrá heuristika ⇒ výrazné zrychlení, projdeme pouze malou část stromu
• špatná heuristika ⇒ nic se neděje, o řešení nepřijdeme (heuristika pouze mění pořadí, ve kterém jsou podstromy procházeny)
Příklady prořezávání a heuristik viz dále...
Jan Hnilica Počítačové modelování 15 6
Prohledávání do hloubky
Luštění Sudoku • tabulka 9 × 9, uvnitř dále rozdělená na 9 bloků 3 × 3 • vyplňujeme čísly 1 – 9, zadání je částečně předvyplněno • omezení: v žádném sloupci, řádku ani bloku se žádné číslo nesmí opakovat
Základní řešení (hromotlucké) • rekurzivní algoritmus, do každého volného políčka postupně zkoušíme čísla 1 – 9 • po vyplnění celé tabulky vždy otestujeme, zda jsme našli řešení
(tzn. zda jsme vytvořili korektní sudoku podle daných omezení)
Časová složitost • 81 políček, na každém hodnoty 1 – 9
• celkem 981 variant ⇒ nelze prohledat v rozumném čase!!!
Urychlení pomocí prořezávání • po vyplnění každého políčka ihned otestujeme, zda jsme neporušili pravidla
⇒ test sloupce, řádku a bloku • pokud ano, nemá smysl větev rozvíjet dál ⇒ ihned návrat o patro výš • ušetříme mnoho zbytečné práce, výrazné zrychlení
Jan Hnilica Počítačové modelování 15 7
Prohledávání do hloubky
Koňská procházka • na šachovnici stojí samotný kůň, cílem je nalézt takovou posloupnost tahů, při které kůň
postupně proskáče celou šachovnici a na žádné pole přitom neskočí dvakrát
Algoritmus
• z každé pozice postupně zkoušíme provést všechny tahy, které vedou na dosud nenavštívená pole, čímž vznikají nové pozice, které rekurzivně rozvíjíme stejným postupem
• z dané pozice
· jsou možné další tahy ⇒ rekurzivní rozvoj
· nejsou možné další tahy ⇒ slepá ulička, návrat o patro výš
· vždy samozřejmě kontrolujeme, zda jsme nedosáhli řešení
Urychlení pomocí heuristiky
• přednostně provádíme ty tahy, které vedou do omezených pozic (tzn. do pozic s menším počtem možných pokračování)
• velmi výrazné zrychlení výpočtu (pokud hledáme jedno řešení)
Jan Hnilica Počítačové modelování 15 8
Prohledávání do hloubky
Koňská procházka
Realizace (jedna z možností)
• šachovnice = 2D pole int [8][8], hodnota políčka = pořadí kroku, kterým jsme na něj přišli
• rekurzivní funkce, pracující nad jediným polem v paměti (š. předávaná jako parametr)
• úvod: všechna políčka šachovnice mají hodnotu 0, startovní pozice má hodnotu 1
• rozvoj z pozice P na pozici P´ (další tah):
· zapsat na P´ číslo o jedničku vyšší než má P
· rekurzivní rozvoj pozice P´
· návrat z rozvoje P´:
· ve větvi bylo nalezeno řešení ⇒ návrat zpět (oznámit čekajícím funkcím nahoře)
· řešení nalezeno nebylo ⇒ vrátit na P´ hodnotu 0 a pokračovat rozvojem jiného tahu
• informace o nalezeném řešení:
· např. proměnná typu int, předávaná mezi funkcemi odkazem
· nebo návratová hodnota samotné rekurzivní funkce
Jan Hnilica Počítačové modelování 15 9
Prohledávání do hloubky
Koňská procházka
• jedno z možných řešení (start vlevo nahoře)
Jan Hnilica Počítačové modelování 15 10
Prohledávání do hloubky
a b c d e f g h
8 1 4 57 20 41 6 43 22 8
7 34 19 2 5 58 21 40 7 7
6 3 56 35 60 37 42 23 44 6
5 18 33 48 53 46 59 8 39 5
4 49 14 55 36 61 38 45 24 4
3 32 17 52 47 54 27 62 9 3
2 13 50 15 30 11 64 25 28 2
1 16 31 12 51 26 29 10 63 1
a b c d e f g h
• = algoritmus vlny, BFS (breadth first search)
Algoritmus • současně rozvíjíme všechny varianty pokračování řešené úlohy
• strom výpočtu procházíme do šířky po vrstvách
Realizace • uzly určené k dalšímu zpracování odkládáme do fronty
• informace o zpracovávaných uzlech lze také zakódovat do reprezentace stavového prostoru (např. šachovnice = 2D pole, políčka obsahují informaci, zda byla už navštívena, popř. v kolikátém kroku)
Paměťová složitost • ve frontě uložena celá vrstva, šířka vrstvy s hloubkou exponenciálně roste
⇒pro větší hloubky výpočtu paměťově nerealizovatelné
Časová složitost • = obecně všechny uzly stromu (jako u backtrackingu)
• ⇒ algoritmus používáme, pokud chceme nalézt nejrychleji dostupné řešení (BFS vždy jako první najde toto řešení)
Jan Hnilica Počítačové modelování 15 11
Prohledávání do šířky
Královská procházka • král stojí na šachovnici na startovním poli S, jeho úkolem je dostat se na cílové pole C
• omezení: na některých polích jsou překážky, na tato pole král nesmí vstoupit
• cílem je zjistit nejmenší možný počet kroků z S na C, případně vypsat cestu
Jan Hnilica Počítačové modelování 15 12
Prohledávání do šířky
start
cíl
překážka
Algoritmus
• okolo výchozí pozice najdeme a označíme všechna pole, na které král může vstoupit
• všechny označené pozice souběžně rozvíjíme, tzn. pro každou z nich najdeme všechny dosud nenavštívené sousedy, na které je možné vstoupit a označíme je pro rozvoj v dalším kroku
• kolem výchozí pozice se v jednotlivých krocích rozlévá „vlna“, která postupně dojde na cílové pole (nebo nedojde, pokud je král překážkami odříznut od cíle)
Jan Hnilica Počítačové modelování 15 13
Prohledávání do šířky
start
cíl
překážka
1. krok
čelo vlny
2. krok 3. krok
4. krok 5. krok 6. krok
9. krok jsme u cíle po 9 krocích 7. krok 8. krok
prohledaná oblast
Královská procházka
Královská procházka
Technická realizace
• šachovnice opět nejlépe jako 2D pole int hodnota políčka = pořadí kroku, kterým se na něj dá dostat
• uložení aktuálně rozvíjených pozic
• lineární seznam
• nebo v každém kroku projít celou šachovnici a nalézt pole s příslušnou hodnotou (nemusíme udržovat lineární seznam, ale přístup k rozvíjeným pozicím je pomalejší)
Výpis konkrétní cesty
• vyžaduje zpětný chod od cílové pozice ke startu
• v každém kroku postupujeme na pole s hodnotou o jedničku menší (takových polí může být víc, teoreticky je jedno, které zvolíme)
Jan Hnilica Počítačové modelování 15 14
Prohledávání do šířky
Přelévání vody
• máme n nádob o definovaných objemech, první je plná, ostatní prázdné
• cíl: pomocí přelévání vody mezi nádobami dosáhnout požadovaných obsahů vody v jednotlivých nádobách
• omezení: nádoby nemají žádné rysky, takže jediné povolené operace, při kterých udržíme informaci o obsahu vody v nádobách jsou:
• úplné vylití nádoby do jiné nádoby
• úplné naplnění nádoby obsahem (nebo částí obsahu) jiné nádoby
• úkol: napsat program, který pro zadané objemy nádob vypíše nejkratší posloupnost přelití, kterou se lze dostat do cílového stavu
Jan Hnilica Počítačové modelování 15 15
Prohledávání do šířky
10 0 0
10 7 2
5 5 0 úvodní stav:
objemy nádob:
cílový stav:
⇒
Přelévání vody
Řešení
• v každém kroku současně rozvíjíme všechny stavy vzniklé v předchozím kroku až do nalezení cílového stavu (nebo do zjištění, že nové stavy už vznikat nemůžou ⇒ úlohu nelze splnit)
Realizace stavového prostoru
• n-rozměrné pole (souřadnice reprezentují aktuální obsahy), prvky pole obsahují pořadí kroku, případně další informace (ze kterého stavu se sem dojde na nejmenší počet kroků...)
• obecný strom stavů uzly obsahují aktuální obsahy, pointery na syny, případně pointer na otce
• při rozvoji je dobré dát pozor na duplicitní rozvoj stejných stavů (z A se lze dostat jedním přelitím na B ⇒ z B se lze dostat zpětným přelitím na A)
Vypsání posloupnosti přelití po nalezení cílového stavu
• zpětný chod stavovým prostorem
• zpětný chod stromem od listu ke kořeni (⇒ tady se bude hodit ten pointer na otce)
Jan Hnilica Počítačové modelování 15 16
Prohledávání do šířky
Přelévání vody
• řešení úlohy
Jan Hnilica Počítačové modelování 15 17
Prohledávání do šířky
10 0 0
10 7 2
3 7 0
3 5 2 5 5 0
• záleží na zadané úloze
Prohledávání do hloubky
• vhodné, pokud je úkolem nalézt
• všechna řešení
• optimální řešení
• ⇒ nutné prohledat celý strom, což trvá u obou algoritmů stejně dlouho, ale prohledávání do hloubky spotřebuje výrazně méně paměti
• nebo pokud hledáme libovolné řešení, které je ale ve stromu daleko od kořene (stejný důvod)
Prohledávání do šířky
• při úkolu nalézt nejrychleji dostupné řešení
• pokud ve velkém stavovém prostoru existuje řešení blízko kořene
Jan Hnilica Počítačové modelování 15 18
Kdy použít který algoritmus
• algoritmus, který umí "inteligentně" hrát např. piškvorky, dámu, šachy...
• obecně hry pro dva hráče, ve kterých jsou veškeré informace viditelné na hrací ploše (ne tedy např. karetní hry)
Hra
• dva hráči (černý a bílý) se pravidelně střídají v tazích
• algoritmus hraje např. v pozici bílého protihráč = člověk (nebo jiný algoritmus)
• cílem algoritmu je vždy v aktuální herní situaci vybrat nejlepší tah
Jan Hnilica Počítačové modelování 15 19
Minimax
z partie Garry Kasparov vs Deep Blue
Strom hry
• uzel = stav na šachovnici (kořen je výchozí stav)
• synové uzlu = možné tahy (vznikají nové stavy)
• bílé uzly ... na tahu je bílý černé uzly ... na tahu je černý
• list = konec hry (výhra jednoho z hráčů nebo remíza)
Jan Hnilica Počítačové modelování 15 20
Minimax
Velikost stromu hry
• obvykle velká hloubka stromu - hry končí až po desítkách tahů
• obvykle velký stupen větvení - uzly mívají desítky synů (počet možných tahů z daného stavu)
⇒ kompletní strom hry bývá velmi rozsáhlý
Hodnota stavu na šachovnici • = číslo, vyjadřující např. aktuální herní materiál hráčů, bonusy za výhodné pozice atd.
• vysoká hodnota ⇒ výhodná pro bílého nízká hodnota ⇒ výhodná pro černého
Princip algoritmu • generuje se strom hry pro daný (omezený) počet tahů dopředu
• nejdříve se ohodnotí listy stromu
• uzly ve vyšších patrech získávají hodnotu postupně při průchodu stromem zdola nahoru
• uzel vždy získá hodnotu toho syna, kterého si daný hráč vybere jako svůj nejlepší tah
bílý maximalizuje ⇒ z možných tahů vybírá ten s nejvyšší hodnotou
černý minimalizuje ⇒ z možných tahů vybírá ten s nejnižší hodnotou
• v kořeni nakonec bílý vybírá tah s nejvyšší hodnotou
Technická realizace • strom hry nelze celý vygenerovat a uložit do paměti (ani u malých her)
⇒ strom se zároveň tvoří a prochází do hloubky, při návratu se uzly ve spodních patrech mažou
• hodnota v uzlu se průběžně upravuje při návratu z jeho podstromu
(v bílém uzlu - pokud se zespoda vrátí hodnota vyšší než prozatím dosažená, v černém naopak)
Jan Hnilica Počítačové modelování 15 21
Minimax
Jan Hnilica Počítačové modelování 15 22
Minimax
1 4
4 1 9 6
4 6 3 2 9 2 1
4
nejdříve ohodnotíme listy .........
vybíráme maximum ......................
vybíráme minimum ................................
vybíráme maximum ............................................ (provede se levý tah)
(demonstrace do hloubky 3 tahů)
Jan Hnilica Počítačové modelování 15 23
Minimax
int Minimax(sachovnice * S, int hloubka, int hrac) { // jsme v listu => vracíme hodnotu na šachovnici if (hloubka == 0) return Hodnota(S); // vygenerujeme tahy z aktuální pozice tah tahy[] = VygenerujTahy(S); int hodnota; int nejHodnota = -hrac * ∞; // postupně vyzkoušíme všechny tahy a zjistíme jejich cenu for (int i = 0; i < pocetTahu; i++) { ZahrajTah(S, tahy[i]); hodnota = Minimax(S, hloubka – 1, -hrac); ZahrajTahZpet(S, tahy[i]); if (hrac == 1) if (hodnota > nejHodnota) nejHodnota = hodnota; if (hrac == -1) if (hodnota < nejHodnota) nejHodnota = hodnota; } // úklid a návrat do vyšších pater SmazTahy(tahy); return nejHodnota; }
(nárys funkce)
Jan Hnilica Počítačové modelování 15 24
Minimax
Složitost minimaxu • paměť = výška stromu (není problém)
• čas = počet uzlů stromu hry, exponenciálně roste s hloubkou ⇒ nutno velmi omezit hloubku prohledávání
Možnosti prořezávání • subjektivní prořezávání (ztrátové)
· po několika tazích zhodnotit stav na šachovnici, pozice, které se jeví jako málo nadějné dál nerozvíjíme
· problém: hodnocení je subjektivní, pouze odhadujeme, jak by se stav mohl rozvinout ⇒ můžeme odmítnout cesty vedoucí nakonec k vítězství
• alfa-beta prořezávání (bez ztráty informace)
· algoritmus doplníme o dva parametry:
· alfa = maximum, které má ve vyšších patrech k dispozici maximalizující hráč
· beta = minimum, které má ve vyšších patrech k dispozici minimalizující hráč
· příklad použití: na tahu je bílý a zjistí, že některý jeho tah má hodnotu > beta ⇒ okamžitý návrat proč? zkoumáním dalších tahů by mohl hodnotu svého uzlu jen zvětšit, ale minimalizující hráč má někde nahoře k dispozici menší hodnotu, tuto větev si tedy stejně nevybere, tzn. nemá cenu pokračovat