Úvod do programování 12. hodina RNDr. Jan Lánský, Ph.D. Katedra informatiky a matematiky Fakulta ekonomických studií Vysoká škola finanční a správní 2015
Úvod do programování 12. hodina Umíme z minulé hodiny Zásobník Create, Push, Pop, Top, IsEmpty Fronta Create, Enqueue, Dequeue, Front, IsEmpty Cyklická fronta, fronta s posunem, prioritní fronta Backtracking - úvod N-ciferná čísla (variace s opakováním) doplnění znamének Jan Lánský Úvod do programování 12. hodina
Úvod do programování 12. hodina Cíle hodiny Backtracking Problém N dam Normální magické čtverce Jezdcova procházka Ořezávání Heuristiky Vlna Cesta koněm po šachovnici Jan Lánský Úvod do programování 12. hodina
Problém N dam 8 dam: Max Bezzel 1848 N dam: Franz Nauck 1850 Rozmístit N dam na šachovnici N x N, tak aby se neohrožovaly. Žádné dvě dámy nesmějí být ve stejném řádku nebo ve stejném sloupci nebo ve stejné úhlopříčce. Nejznámější varianta 8 dam na šachovnici 8x8 má 92 řešení. Najdeme všechna řešení backtrackingem 12 základních, zbytek symetrická Jan Lánský Úvod do programování 12. hodina
Problém 8 dam Šachová terminologie: Šachovnice má 64 hracích polí. Aby se nám "hrací pole" nepletlo s polem jako datovou strukturou, budeme používat "políčko" D Jedno z možných řešení problému Pro dvě vybrané dámy je znázorněno jaká políčka ohrožují. Jan Lánský Úvod do programování 12. hodina
Problém N dam algoritmus Obvykle se nepoužívá pole pro pamatování hrozeb, ale hrozby se kontrolují na místě. Moje řešení mě přijde pochopitelnější. Na každém řádku musí být 1 dáma. Postupně vyzkoušíme všechna umístění 1. dámy na 1. řádku a pro ně rekurzivně umístíme 2. dámu na 2. řádek Pro každé políčko šachovnice si pamatujeme, kolika dříve umístěnými dámami je ohrožováno. Na ohrožené políčko nebudeme dámu umisťovat. Pokud nelze na daném řádku umísit žádnou dámu, vracíme se z rekurze. Při návratu z rekurze musíme upravit počet ohrožení pro políčka, která byla ohrožována dámou, jejíž umístění vracíme. Pokud jsme umístili všech N dam, vypíšeme výsledek. Jan Lánský Úvod do programování 12. hodina
Výpis šachovnice Dáma = true, volno = false Šachovnice 0 až (N – 1) x 0 až (N – 1). V levém horním rohu je políčko s indexem [0,0] Dáma D, prázdné políčko tečka Jan Lánský Úvod do programování 12. hodina
Příprava na rekurzi Rekurze začíná na řádku 0 Dvojrozměrné pole hrozby: hodnota prvků udává počet dam, která se nacházejí na nižších řádcích a ohrožují políčko reprezentované daným prvkem Vracíme počet řešení Nesledujeme hrozby dam z vyšších řádků. Tyto dámy budou odstraněny při návratu z rekurze, dříve než budeme s prvkem pracovat U hrozeb musíme znát jejich počet, nestačí bool (kvůli návratu z rekurze) Jan Lánský Úvod do programování 12. hodina
Dvojrozměrné pole hrozby 1 2 3 4 5 6 7 První řádek musí být nulový z definice (není žádná dáma na nižším řádku Červená políčka – je na nich umístěna dáma Prvek [4,6] má hodnotu 1. Ohrožuje ho jen jedna dáma z nižšího řádku [3, 5]. Dámy [4,2], [5,6] a [7,3] jsou na vyšších řádcích. Jan Lánský Úvod do programování 12. hodina
N dam bylo umístěno, vypíšeme řešení. Počítáme počet řešeni – return 1 Pokusíme se umístit dámu do každého sloupce, vynecháme ohrožované sloupce Řádky i, sloupce j Nastavíme hrozby od dámy, kterou budeme umísťovat. 1. umístíme dámu 2. rekurze pro další řádek 3. odebereme dámu Odebereme hrozby po odebrané dámě Při návratu z rekurze jsme sčítali počty řešení Jan Lánský Úvod do programování 12. hodina
Hrozby Hrozby nastavujeme jen na řádky, které následují po aktuálním řádku Proto podmínka cyklu i+radek < Length(1) Proto první index pole i + radek sloupce Diagonály doprava a doleva Testy, zda jsme ještě na šachovnici 0 až N - 1 D j-i j j+i Indexy sloupce Jan Lánský Úvod do programování 12. hodina
Úvod do programování 12. hodina Klasické řešení Učebnicové řešení Nepoužívá pole hrozby, ale pro políčko kam chceme umístit dámu provede kontrolu zda není ohrožováno nějakou dámou umístěnou ve sloupci nebo diagonálách nad políčkem Pro 8 dam 1,5 x pomalejší, pro 13 dam 3x pomalejší Jan Lánský Úvod do programování 12. hodina
Klasické řešení Nepotřebujeme pole hrozby N dam bylo umístěno, vypíšeme řešení. Počítáme počet řešeni – return 1 Pokusíme se umístit dámu do každého sloupce Ohrožení testuje funkce Umístíme dámu; rekurze pro další řádek; odebereme dámu Jan Lánský Úvod do programování 12. hodina
Ohrožení sloupce Levá diagonála Pravá diagonála Cyklus o dvou řídících proměnných pro průchod diagonálami: Řídící proměnné i a j. V inicializaci a inkrementu je oddělíme příkazy pro jednotlivé řídící proměnné operátorem čárky. V podmínce testujeme konjunkci podmínek pro jednotlivé řídící proměnné. Není moc obvyklé řešení, lze rozepsat while cyklem … Jan Lánský Úvod do programování 12. hodina
Normální magické čtverce Čína, 650 př. n. l. Normální magický čtverec N x N obsahuje čísla 1 až N umístěna tak, že všechny řádky i sloupce i obě diagonály mají shodný součet hodnot čísel v nich umístěných. Součet čísel 1 až N2 je N2 (N2+1)/2 Součet hodnot čísel v řádku / sloupci N(N2+1)/2 N = 3, S = 15; N = 4, S = 34; N = 5, S = 65 Podobný princip sudoku Pro N = 2 nejde Jan Lánský Úvod do programování 12. hodina
Normální magický čtverec 4x4 Součet každé řádky, každého sloupce i každé úhlopříčky je 34 34 1 15 14 4 12 6 7 9 8 10 11 5 13 3 2 16 Jan Lánský Úvod do programování 12. hodina
Normální magické čtverce: Algoritmus Ořezávání: nepokračujeme, když daná větev nemůže vést k řešení Backtracking: Budeme postupně plnit čísly 1. řádek (od 1. sloupce po poslední), 2. řádek … Budeme průběžně uchovávat součet hodnot v plněném řádku, když překročíme stanovenou hodnotu, vracíme se. Budeme průběžně uchovávat součet hodnot ve všech sloupcích a obou diagonálách. Když přidáním prvku překročíme stanovenou hodnotu, vracíme se. Některá řešení lze najít i bez backtrackingu http://mks.mff.cuni.cz/library/MagickeCtverceTR/MagickeCtverceTR.pdf Jan Lánský Úvod do programování 12. hodina
Úvod do programování 12. hodina Ořezávání Backtracking obvykle exponenciální časová složitost. Jakékoliv vylepšení se hodí Pokud při backtrackingu zjistíme, že v danou chvíli nelze kandidáta na řešení žádným způsobem rozšířit na řešení, ukončíme větev rekurze. Čím dříve takového kandidáta ořízneme, tím lépe. Příklady N-ciferná čísla: pokračovali jsme v rekurzi jen pro povolené cifry (ostatní jsme ořízli) N-dam: pokračovali jsme v rekurzi jen pro neohrožená políčka Magické čtverce: pokud řádek nesplňoval požadovaný součet, končili jsme Jan Lánský Úvod do programování 12. hodina
Heuristiky Odhadneme, které prodloužení kandidáta má největší šanci na úspěch a zpracujeme ho přednostně. Obecně určíme pořadí, ve kterém budeme jednotlivá prodloužení kandidáta zpracovávat. Pokud se spleteme, zpomalíme se jen o čas odhadu nejlepšího prodloužení. Řešení najdeme (mírně) později než bez použití heuristiky. Pokud chceme rychle najít jedno řešení a nezajímají nás všechna řešení. Při hledání všech řešení nemají smysl. Zatím jsme heuristiky nepoužívali, hledali jsme všechna řešení Bude: jezdcova procházka V cyklu jsme postupně prošli všechna možná prodloužení Jan Lánský Úvod do programování 12. hodina
Kombinace heuristiky a prořezávání Chceme nalézt nejlepší řešení úlohy podle zadaného kritéria Pomocí heuristiky najdeme rychle nějaké řešení Pomocí ořezávání ukončujeme ty kandidáty na řešení, které jsou v zadaném kritériu horší. Příklad: Hledání nejkratší cesty mezi městy. Pokud kandidát na cestu má větší délku než nejlepší již nalezená cesta, ukončíme ho. Jan Lánský Úvod do programování 12. hodina
Úvod do programování 12. hodina Jezdcova procházka Zadána startovní pozice jezdce na šachovnici NxN. Cílem je navštívit každé políčko šachovnice právě jednou Varianta zakončit cestu na políčku sousedícím se startovním (nebudeme řešit) Šachovnice 8x8 Backtracking do úrovně 64 Počet řešení 33 439 123 484 294 Budeme hledat pouze jedno Řešení: Backtracking Jan Lánský Úvod do programování 12. hodina
Pohyb jezdce 1 2 3 4 5 6 7 J 8 Jezdec se pohybuje do "L". 1 2 3 4 5 6 7 J 8 Jezdec se pohybuje do "L". Dva tahy v jednom směru (řádek, sloupec) a jeden tah v druhém směru. Tah 1: [-1, -2] Tah 2: [-1, +2] Tah 3: [+1, -2] Tah 4: [+1, +2] Tah 5: [-2, -1] Tah 6: [-2, +1] Tah 7: [+2, -1] Tah 8: [+2, +1] Jan Lánský Úvod do programování 12. hodina
Jezdcova procházka Barva políček od bílé po červenou, jak se blížíme cíli Na šachovnici jsou čísla tahů [2,3][1,1][0,3][1,5] [0,7][2,6][0,5][1,7] [3,6][5,7][7,6][6,4] [7,2][6,0][4,1][2,0] [0,1][1,3][2,1][0,0] [1,2][0,4][1,6][2,4] [3,2][4,0][6,1][7,3] [6,5][7,7][5,6][3,7] [4,5][5,3][7,4][6,6] [4,7][3,5][2,7][0,6] [1,4][0,2][1,0][2,2] [3,0][5,1][7,0][6,2] [4,3][3,1][5,0][7,1] [5,2][4,4][2,5][3,3] [5,4][4,2][3,4][4,6] [6,7][5,5][6,3][7,5]; 1 2 3 4 5 6 7 20 17 42 22 40 43 21 18 41 23 8 16 19 44 24 55 39 45 50 25 56 59 38 9 32 26 15 58 49 54 33 60 37 51 46 53 34 57 62 31 10 14 27 48 63 12 29 36 61 47 52 13 28 35 64 11 30 Jan Lánský Úvod do programování 12. hodina
Příprava na rekurzi Struktura tah na uchování pozice řádku a sloupce Šachovnice obsahuje čísla tahů, kterými jsme na dané políčko vstoupili Nastavíme startovní pozici (= 1.tah) a rekurzi pouštíme pro druhý tah Jan Lánský Úvod do programování 12. hodina
Rekurze Celé pole je projité, vypíšeme tah do souboru Funkce, která vrátí pole možných tahů. V proměnné vrátí navíc počet tahů. Bude jich obvykle méně než je délka pole. 1) Nastavíme tah 2) Pustíme pro něj rekurzi (n+1) 3) Zrušíme tah. Zda jsme nalezli řešení, bude ukončovat rekurzi, viz podmínka cyklu Jan Lánský Úvod do programování 12. hodina
Výpis tahu Časová sloužitost N^4, kde N je hrana šachovnice. Pro každé pořadí tahu najdeme políčko, které bylo daným tahem obsazeno. Nutno při tom projít šachovnici. Pokud by tento postup byl pomalý, jde tahy ukládat na zásobník v průběhu hledání. Tahy vypíšeme do souboru, pro každý tah vypisujeme [řádek, sloupec] Jan Lánský Úvod do programování 12. hodina
Další tahy Maximálně 8 možných tahů, na krajích šachovnice méně. Ke konci hry bude hodně políček obsazených 3 vnořené cykly 1) Absolutní hodnota pohybu v řádku (sloupec se dopočítá) 2) Znaménko pohybu v řádku 3) Znaménko pohybu v sloupci V cyklech inkrementuje řídící proměnnou o 2 Kontrola, zda řádek tahu není mimo šachovnici Kontrola, zda sloupec tahu není mimo šachovnici Kontrola, zda políčko není obsazené Jan Lánský Úvod do programování 12. hodina
Další tahy – alternativní řešení Učebnicové, ale o 50 % pomalejší Všech 8 možných tahů uložíme do pole jako relativní posuny od zadané pozice Cyklus přes všech 8 tahů Ke skutečné pozici přičteme relativní posun Testy zda je tah není mimo šachovnici a zda pole není obsazené Jan Lánský Úvod do programování 12. hodina
Úvod do programování 12. hodina Heuristika H. C. von Warnsdorf, 1823 Navržené řešení je velmi pomalé N = 6 cca 3s, N = 8 ??? Heuristika Upřednostňovat tahy, které vedou na políčka, ze kterých je nejméně možných tahů. Modifikujeme funkci DalsiTahy přeuspořádáme tahy v poli podle počtu možných tahů, které z nich vedou Z exponenciální časové složitosti se stane lineární Jan Lánský Úvod do programování 12. hodina
Další tahy: Heuristika I. Přejmenována funkce Přidáno pole na uložení počtu tahů, které mohou po daném tahu následovat Zavoláme původní funkci DalsiTahy, která pro každý tah vrátí počet možných tahů Jan Lánský Úvod do programování 12. hodina
Další tahy: Heuristika II Šlo by řešit prioritní frontou, ale vzhledem k charakteru dat pomalé Pole tahů musíme setřídit podle hodnot v poli pokračování. Třídíme vzestupně Insertion sortem Třídíme obě dvě pole: Tahy i pokračování, ale pro porovnání při třídění uvažujeme jen hodnoty pole pokračování Jan Lánský Úvod do programování 12. hodina
Algoritmus vlny Varianta: U stromů prohledávání do šířky Současně rozšiřujeme kandidáta na řešení o všechny možné kroky. Vznikne tím více kandidátu na řešení Při backtrackingu jsem rozšiřovali jednoho kandidáta na řešení o jeden vybraný krok dokud to šlo. První najité řešení bude nejkratší. Oproti Backtrackingu paměťově náročnější Využití fronty Při backtrackingu se využíval zásobník Jan Lánský Úvod do programování 12. hodina
Cesta jezdcem na šachovnici Najití nejkratší cesty jezdcem na šachovnici ze zadaného startovního políčka do zadaného cílového políčka Měřeno počtem tahů Umíme najít backtrackingem, ale časově náročné (až 63 tahů místo 6) Algoritmus vlny Jan Lánský Úvod do programování 12. hodina
Cesta jezdcem na šachovnici Dvojrozměrné pole šachovnice Startovní políčko označíme hodnotou 1 Políčka, kam jde táhnout ze startovní pozice označíme 2 Políčka, kam jde táhnout z políček z hodnotou n označíme n+1 Tahy budeme ukládat do fronty Konec, až cílové políčko bude mít přiřazeno číslo udávající počet tahů Rekonstrukce tahů vedoucích k cíli: Pro každé políčko pamatujeme, z jakého políčka jsme se na něj dostali Jan Lánský Úvod do programování 12. hodina
Cesta jezdcem na šachovnici 1 2 3 4 5 6 7 Start: zelená Cíl červená Cesta: [3,3] [1,4] [2,2] [4,3] [5,5] Jan Lánský Úvod do programování 12. hodina
Šachovnice s počtem tahů Šachovnice s tahy zpět Musíme frontu upravit, aby pracovala s typem Tah Do fronty dáme startovní pozici jezdce 1. Vyzvedneme tah z fronty 2. Vygenerujeme možné tahy 3. Možné tahy vložíme do fronty 4. Na šachovnici možným tahům nastavíme délku cesty 5. Možným tahům nastavíme cestu zpět na výchozí tah. Vypíšeme jednotlivé tahy Vracíme délku cesty Jan Lánský Úvod do programování 12. hodina
Výpis cesty Pole cesta bude mít nevyužitý prvek s indexem nula Cestu získáváme od cíle, pomocí tahů zpět Výpis na obrazovku od prvku s indexem 1 Jan Lánský Úvod do programování 12. hodina
Úvod do programování 12. hodina Zpětná vazba Objevili jste ve slajdech chyby? Včetně pravopisných Nechápete nějaký slajd? Je příliš obtížný, nesrozumitelný? Máte nějaký nápad na vylepšení? Anonymní formulář Odeslání za pár vteřin http://goo.gl/forms/WxkZqBsZLs Jan Lánský Úvod do programování 12. hodina