Rozklad problému na podproblémy, rekurze

Podobné dokumenty
Rozklad problému na podproblémy, rekurze

5. přednáška - Rozklad problému na podproblémy

Rozklad problému na podproblémy

Algoritmizace a programování

8. Rekurze. doc. Ing. Jiří Vokřínek, Ph.D. Katedra počítačů Fakulta elektrotechnická České vysoké učení technické v Praze

Dekompozice problému, rekurze

Funkce, intuitivní chápání složitosti

4. Rekurze. BI-EP1 Efektivní programování Martin Kačer

Řídící struktury, if, while, switch

Algoritmizace a programování

5. Dynamické programování

Rekurze. Pavel Töpfer, 2017 Programování 1-8 1

Algoritmizace a programování

Algoritmizace a programování

Rekurze. doc. Mgr. Jiří Dvorský, Ph.D. Katedra informatiky Fakulta elektrotechniky a informatiky VŠB TU Ostrava. Prezentace ke dni 12.

Řídící struktury, if, while, switch

Základy algoritmizace 4. Problémy, algoritmy, data

3. přednáška. Obsah: Řídící struktury sekvence, if-else, switch, for, while, do-while. Zpracování posloupnosti

Operační systémy. Cvičení 4: Programování v C pod Unixem

Řídicí struktury. alg3 1

- jak udělat konstantu long int: L long velka = 78L;

Jazyk C++, některá rozšíření oproti C

Program převod z desítkové na dvojkovou soustavu: /* Prevod desitkove na binarni */ #include <stdio.h>

1. lekce. do souboru main.c uložíme následující kód a pomocí F9 ho zkompilujeme a spustíme:

BI-EP1 Efektivní programování 1

Funkce a procedury. Jan Faigl. Katedra počítačů Fakulta elektrotechnická České vysoké učení technické v Praze. Přednáška 5 A0B36PR1 Programování 1

BI-PA1 Programování a algoritmizace 1 Katedra teoretické informatiky

Část 1 Funkce, lokální proměnné a přidělování paměti. Funkce a procedury. Část 2 Cykly a řízení jejich průchodu. Část 3 Příklady

Dynamické programování

8. lekce Úvod do jazyka C 3. část Základní příkazy jazyka C Miroslav Jílek

Algoritmizace. Cíle předmětu

Algoritmizace Dynamické programování. Jiří Vyskočil, Marko Genyg-Berezovskyj 2010

Programování v jazyce C pro chemiky (C2160) 3. Příkaz switch, příkaz cyklu for, operátory ++ a --, pole

Algoritmizace a programování. Ak. rok 2012/2013 vbp 1. ze 44

Prohledávání do šířky = algoritmus vlny

9. lekce Úvod do jazyka C 4. část Funkce, rekurze Editace, kompilace, spuštění Miroslav Jílek

Programování a algoritmizace

BI-PA1 Programování a algoritmizace 1 Katedra teoretické informatiky

Rekurzivní algoritmy

Výrazy a operátory. Operátory Unární - unární a unární + Např.: a +b

BI-PA1 Programování a algoritmizace 1 Katedra teoretické informatiky

BI-PA1 Programování a algoritmizace 1 Katedra teoretické informatiky

1. lekce. do souboru main.c uložíme následující kód a pomocí F9 ho zkompilujeme a spustíme:

Programování: základní konstrukce, příklady, aplikace. IB111 Programování a algoritmizace

BI-PA1 Programování a algoritmizace 1, ZS Katedra teoretické informatiky

Struktura programu v době běhu

Seminář z IVT Algoritmizace. Slovanské gymnázium Olomouc Tomáš Kühr

Větvení a cykly. Úvod do programování 1 Tomáš Kühr

BI-PA1 Programování a algoritmizace 1, ZS Katedra teoretické informatiky

Začínáme vážně programovat. Řídící struktury Přetypování Vstupně výstupní operace Vlastní tvorba programů

Vyhledávání. doc. Mgr. Jiří Dvorský, Ph.D. Katedra informatiky Fakulta elektrotechniky a informatiky VŠB TU Ostrava. Prezentace ke dni 21.

Funkce, procedury, složitost

Racionální čísla, operátory, výrazy, knihovní funkce

Cykly. Základy programování 1 Martin Kauer (Tomáš Kühr)

Vyhledávání. doc. Mgr. Jiří Dvorský, Ph.D. Katedra informatiky Fakulta elektrotechniky a informatiky VŠB TU Ostrava. Prezentace ke dni 12.

Řešení sady 1. Úvod do programování 1 Tomáš Kühr

BI-PA1 Programování a algoritmizace 1 Katedra teoretické informatiky

2 Základní funkce a operátory V této kapitole se seznámíme s použitím funkce printf, probereme základní operátory a uvedeme nejdůležitější funkce.

Příkazy if, while, do-while, for, switch

BI-PA1 Programování a algoritmizace 1 Katedra teoretické informatiky

C++ Akademie SH. 2. Prom nné, podmínky, cykly, funkce, rekurze, operátory. Michal Kvasni ka. 20. b ezna Za áte níci C++

Základy algoritmizace a programování

Funkce pokročilé možnosti. Úvod do programování 2 Tomáš Kühr

for (i = 0, j = 5; i < 10; i++) { // tělo cyklu }

V každém kroku se a + b zmenší o min(a, b), tedy vždy alespoň o 1. Jestliže jsme na začátku dostali 2

Rekurze. Jan Hnilica Počítačové modelování 12

Řešení: PŘENESVĚŽ (N, A, B, C) = přenes N disků z A na B pomocí C

Úvod do programování 10. hodina

Abstraktní třídy, polymorfní struktury

Informatika navazující magisterské studium Přijímací zkouška z informatiky 2018 varianta A

Rekurze. IB111 Úvod do programování skrze Python

Racionální čísla, operátory, výrazy, knihovní funkce

Úvod do informatiky. Miroslav Kolařík

5 Rekurze a zásobník. Rekurzivní volání metody

Úvod do programování. Lekce 5

Př. další použití pointerů

Binární soubory (datové, typované)

PROGRAMOVACÍ JAZYKY A PŘEKLADAČE REALIZACE PŘEKLADAČE I

Programování v Pythonu

VYŠŠÍ ODBORNÁ ŠKOLA a STŘEDNÍ PRŮMYSLOVÁ ŠKOLA Mariánská 1100, Varnsdorf PROGRAMOVÁNÍ FUNKCE, REKURZE, CYKLY

Jazyk C Program v jazyku C má následující strukturu: konstanty nebo proměnné musí Jednoduché datové typy: Strukturované datové typy Výrazy operátory

Poslední nenulová číslice faktoriálu

Logické operace. Datový typ bool. Relační operátory. Logické operátory. IAJCE Přednáška č. 3. může nabýt hodnot: o true o false

Pole a Funkce. Úvod do programování 1 Tomáš Kühr

Slepé prohledávání do šířky Algoritmus prohledávání do šířky Při tomto způsobu prohledávání máme jistotu, že vždy nalezneme koncový stav, musíme ale p

KTE / ZPE Informační technologie

Základy algoritmizace a programování

Mělká a hluboká kopie

Algoritmizace a programování

Programovani v Maplu Procedura

Základní datové typy, proměnné - deklarujeme předem - C je case sensitive rozlišuje malá a velká písmena v názvech proměnných a funkcí

Algoritmizace. Algoritmizace (Y36ALG), Šumperk - 1. přednáška 1

68. ročník Matematické olympiády 2018/2019

Úvod do programování - Java. Cvičení č.4

Algoritmy I. Cvičení č. 2, 3 ALGI 2018/19

2 Strukturované datové typy Pole Záznam Množina... 4

Úvod do programovacích jazyků (Java)

Programování v C++ 1, 1. cvičení

IB111 Úvod do programování skrze Python

6 Příkazy řízení toku

Transkript:

Příprava studijního programu Informatika je podporována projektem financovaným z Evropského sociálního fondu a rozpočtu hlavního města Prahy. Praha & EU: Investujeme do vaší budoucnosti Rozklad problému na podproblémy, rekurze BI-PA1 Programování a algoritmizace 1, ZS 2014-2015 Katedra teoretické informatiky Miroslav Balík Fakulta informačních technologií České vysoké učení technické

Rozklad problému na podproblémy Postupný návrh programu rozkladem problému na podproblémy zadaný problém rozložíme na podproblémy pro řešení podproblémů zavedeme abstraktní příkazy s pomocí abstraktních příkazů sestavíme hrubé řešení abstraktní příkazy realizujeme pomocí metod Rozklad problému na podproblémy ilustrujme na příkladu hry NIM Pravidla: hráč zadá počet zápalek ( např. od 15 do 35 ) pak se střídá se strojem v odebírání; odebrat lze 1, 2 nebo 3 zápalky, prohraje ten, kdo odebere poslední zápalku. Dílčí podproblémy: zadání počtu zápalek odebrání zápalek hráčem odebrání zápalek strojem Ing. Miroslav Balík, Ph.D. - BI-PA1-06 2/28

Hrubé řešení: int pocet; bool stroj = false; zadání počtu zápalek do { Hra NIM if (stroj) odebrání zápalek strojem else odebrání zápalek hráčem stroj =!stroj; while (pocet > 0); if (stroj) vyhrál stroj v hrubém řešení použijeme typ bool, jehož hodnotami jsou true a false else vyhrál hráč Podproblémy zadání počtu zápalek, odebrání zápalek strojem a odebrání zápalek hráčem budeme realizovat procedurami, proměnné pocet a stroj budou globálními (pro procedury nelokálními) proměnnými Ing. Miroslav Balík, Ph.D. - BI-PA1-06 3/28

Hra NIM /* prog6-nim.c */ #include <stdio.h> #include <stdlib.h> co je typ bool? #define bool char #define true 1 #define false 0 co je to false? int pocet; Vysvětlení na dalším slajdu bool stroj = false; /* zacina hrac */ void zadanipoctu(void) { do { printf("zadejte pocet zapalek (od 15 do 35): "); scanf("%d", &pocet); while (pocet<15 pocet>35); void berehrac(void) { int x; bool chyba; do { chyba = false; printf("pocet zapalek je %d\n", pocet); printf("kolik odeberete: "); scanf("%d", &x); Ing. Miroslav Balík, Ph.D. - BI-PA1-06 4/28

Hra NIM if (x<1) { printf("prilis malo\n"); chyba = true; else if (x>3 x>pocet) { printf("prilis mnoho\n"); chyba = true; while (chyba); pocet -= x; void berestroj(void) { printf("pocet zapalek je %d\n", pocet); int x = (pocet-1)%4; if (x==0) x = 1; printf("odebiram %d\n", x); pocet -= x; int main(void) { zadanipoctu(); do { if (stroj) berestroj(); else berehrac(); stroj =!stroj; while (pocet>0); if (stroj) printf("vyhral jsem\n"); else printf("vyhral jste, gratuluji\n"); return 0; Ing. Miroslav Balík, Ph.D. - BI-PA1-06 5/28

/* prog6-nim.c */ Direktiva define #define bool char #define true 1 #define false 0 int pocet; bool stroj = false; direktiva pro předprocesor každý výskyt tohoto identifikátoru bude nahrazen tímto textem místo false bude 0 místo bool bude char takže překladač zpracuje deklaraci proměnné stroj takto char stroj = 0; Ing. Miroslav Balík, Ph.D. - BI-PA1-06 6/28

Hra NIM Pravidla pro odebírání zápalek strojem, která vedou k vítězství (je-li to možné): počet zápalek nevýhodných pro protihráče je 1, 5, 9, atd., obecně 4n+1, kde n >=0, stroj musí z počtu p zápalek odebrat x zápalek tak, aby platilo p x = 4n + 1 z tohoto vztahu po úpravě a s ohledem na omezení pro x dostaneme x = (p 1) % 4 vyjde-li x=0, znamená to, že okamžitý počet zápalek je pro stroj nevýhodný a bude-li protihráč postupovat správně, stroj prohraje. void berestroj(void) { printf("pocet zapalek je %d\n", pocet); int x = (pocet-1)%4; if (x==0) x = 1; printf("odebiram %d\n", x); pocet -= x; Ing. Miroslav Balík, Ph.D. - BI-PA1-06 7/28

Rekurze Definice ze slovníku (pozor vtip) Rekurze viz Rekurze.nekonečná rekurze, lépe: pokud neznáte význam tohoto pojmu, pokračujte pojmem Rekurze Rekurze - algoritmus, který volá v průběhu svého běhu sama sebe Příklad: výpočet faktoriálu: n! 0! = 1, 1! = 1, pro záporné číslo x budiž x! = 1 pro n>1 n! = n(n-1)! Ing. Miroslav Balík, Ph.D. - BI-PA1-06 8/28

Faktoriál pomocí rekurze a iterace n! = 1 pro n 1 n! = n*(n-1)! pro n>1 int fakt(int n) { int fakt(int n) { int f = 1; int fakt(int n) { if (n<=1) return while 1; (n>1){ if (n<=1) return 1; return n * fakt(n-1) f *= n; else return n * fakt(n-1); n--; return f; int fakt(int n) { return n<=1?1:n * fakt(n-1); // ternární operátor Ing. Miroslav Balík, Ph.D. - BI-PA1-06 9/28

Iterační alg. NSD(), připomenutí int nsd(int x, int y) { int zbytek; while ( y!= 0 ) { zbytek = x % y; x = y; y = zbytek; return x; Kolikrát se provede tělo cyklu while? Platí: Je-li x y (> 0), pak x mod y < x/2 Důkaz: (55 88, 88 55, 55 33, 33 22, 22 11, 11 11, 11 0) buď je y x/2 nebo je y > x/2 y y y x / 2 y x x mod y x / 2 y x x mod y Nechť n je počáteční hodnota y. Každé dva průchody cyklem se y zmenší na polovinu, takže na hodnotu 0 dospěje nejpozději po 2.log 2 n průchodech. Ing. Miroslav Balík, Ph.D. - BI-PA1-06 10/28

Rekurzivní algoritmus NSD() I Platí: je-li x, y > 0, pak nsd(x, y): je-li x = y, pak nsd(x,y) = x je-li x > y, pak nsd(x,y) = nsd(x%y,y) je-li x < y, pak nsd(x,y) = nsd(x,y%x) int nsd(int x, int y) { if (x==y) return x; else if (x>y) return nsd(x%y, y); else return nsd(x, y%x); Rekurze int nsd(int x, int y) { int zbytek; while( y!= 0 ) { zbytek = x % y; x = y; y = zbytek; return x; Iterace Ing. Miroslav Balík, Ph.D. - BI-PA1-06 11/28

Příklad: Rekurze a rozklad problému na podproblémy Program, který přečte posloupnost čísel zakončenou nulou a vypíše ji obráceně Rozklad problému: zavedeme abstraktní příkaz obrať posloupnost příkaz rozložíme do tří kroků: přečti číslo ( a ulož si ho ) if (přečtené číslo není nula) obrať posloupnost ( zbytek!! ) vypiš číslo ( uložené ) Ing. Miroslav Balík, Ph.D. - BI-PA1-06 12/28

Příklad rekurze Obrať posloupnost obrať posloupnost přečti číslo if (přečtené číslo není nula) obrať posloupnost, tj. zbytek vypiš číslo cti x if() 2 4 6 8 0 2 cti x if() 4 cti x if() 6 cti x 8 0 0 8 6 4 2 if() cti x 2 piš x 4 piš x 6 piš x 8 if() piš x 0 piš x Ing. Miroslav Balík, Ph.D. - BI-PA1-06 13/28

/* prog6-obrat.c */ #include <stdio.h> #include <stdlib.h> Příklad rekurze - obrat() void obrat(void) { int x; scanf("%d", &x); if (x!=0) obrat(); printf("%d ", x); int main(void) { printf("zadejte posloupnost celych cisel zakoncenou nulou\n"); obrat(); printf("\n"); return 0; Ing. Miroslav Balík, Ph.D. - BI-PA1-06 14/28

Příklad rekurze - Hanojské věže 1 2 3 Úkol: přemístit disky na druhou jehlu s použitím třetí pomocné jehly, přičemž musíme dodržovat tato pravidla: - v každém kroku můžeme přemístit pouze jeden disk, a to vždy z jehly na jehlu (disky nelze odkládat mimo jehly), - není možné položit větší disk na menší. Ing. Miroslav Balík, Ph.D. - BI-PA1-06 15/28

Příklad rekurze - Hanojské věže 1 2 3 Zavedeme abstraktní příkaz: přenes_věž(n,1,2,3), který interpretujeme jako "přenes n disků z jehly 1 na jehlu 2 s použitím jehly 3". Pro n>0 lze příkaz rozložit na tři jednodušší příkazy přenes_věž(n-1,1,3,2) "přenes disk z jehly 1 na jehlu 2", přenes_věž(n-1,3,2,1) Ing. Miroslav Balík, Ph.D. - BI-PA1-06 16/28

Hanojské věže /* prog6-hanoj.c */ /* hanojske veze */ #include <stdio.h> #include <stdlib.h> void prenesvez(int vyska, int odkud, int kam, int pomoci) { if (vyska>0) { prenesvez(vyska-1, odkud, pomoci, kam); printf("prenes disk z %d na %d\n", odkud, kam); prenesvez(vyska-1, pomoci, kam, odkud); int main(void) { int pocetdisku; printf("zadejte pocet disku: "); scanf("%d", &pocetdisku); if (pocetdisku<=0) printf("pocet disku musi byt kladne cislo\n"); else prenesvez(pocetdisku, 1, 2, 3); return 0; Ing. Miroslav Balík, Ph.D. - BI-PA1-06 17/28

Příklad rekurze - Hanojské věže pvez(3, 1, 2, 3) pvez(2, 1, 3, 2) (1, 2) pvez(2, 3, 2, 1) pvez(1,1,2,3) (1,3) pvez(1,2,3,1) pvez(1,3,1,2) (3,2) pvez(1,1,2,3) pvez(0,1,3,2) (1, 2) pvez(0,3,2,1) (2, 3) (3, 1) (1, 2) void prenesvez(int vyska, int odkud, int kam, int pomoci) { if (vyska>0) { 3 prenesvez(vyska-1, odkud, pomoci, kam); přenes disk z 1 na 2 printf("prenes disk z %d na %d\n", odkud, kam); přenes disk z 1 na 3 prenesvez(vyska-1, pomoci, kam, odkud); přenes disk z 2 na 3 přenes disk z 1 na 2 přenes disk z 3 na 1 přenes disk z 3 na 2 přenes disk z 1 na 2 Ing. Miroslav Balík, Ph.D. - BI-PA1-06 18/28

Obecně k rekurzivitě Rekurzivní funkce (procedury) jsou přímou realizací rekurzivních algoritmů Rekurzivní algoritmus předepisuje výpočet shora dolů v závislosti na velikosti (složitosti) vstupních dat: pro nejmenší (nejjednodušší) data je výpočet předepsán přímo pro obecná data je výpočet předepsán s využitím téhož algoritmu pro menší (jednodušší) data Výhodou rekurzivních funkcí (procedur) je jednoduchost a přehlednost Nevýhodou může být časová náročnost způsobená např. zbytečným opakováním výpočtu Řadu rekurzívních algoritmů lze nahradit iteračními, které počítají výsledek zdola nahoru, tj, od menších (jednodušších) dat k větším (složitějším) Pokud algoritmus výpočtu zdola nahoru nenajdeme (např. při řešení problému Hanojských věží), lze rekurzivitu odstranit pomocí tzv. zásobníku Ing. Miroslav Balík, Ph.D. - BI-PA1-06 19/28

Fibonacciho posloupnost - historie Pingala (Chhandah-shāstra, the Art of Prosody, 450 or 200 BC) Leonardo Pisano (Leonardo z Pisy), známý také jako Fibonacci (cca 1175 1250) - králíci Henry E. Dudeney (1857-1930) - krávy Jestliže každá kráva vyprodukuje své první tele (jalovici) ve věku dvou let a poté každý rok jednu další jalovici, kolik budete mít krav za 12 let, jestliže Vám žádná nezemře? rok počet krav (jalovic) 1 1 2 1 3 2 4 3 5 5 6 8 počet krav = počet krav vloni + počet narozených (odpovídá počtu krav předloni) f n = f n-1 + f n-2.. 12 144.. 50 20 365 011 074 (20 miliard) Ing. Miroslav Balík, Ph.D. - BI-PA1-06 20/28

Fibonacciho posloupnost Platí: f 0 = 1 f 1 = 1 f n = f n-1 + f n-2 pro n > 1 Rekurzivní funkce: int fib(int i) { if (i<2) return 1; return fib(i-1)+fib(i-2); Rekurze je hezká - zápis odpovídá rekurentní definici. Je ale i efektivní? Ing. Miroslav Balík, Ph.D. - BI-PA1-06 21/28

Fibonacciho posloupnost - iteračně Platí: f 0 = 1 f 1 = 1 f n = f n-1 + f n-2,pro n > 1 Iteračně: fibnminus2 fibnminu1 fibn int fib(int n) { int i, fibnminus2=1; fibnminus1=1, fibn=1; for (i=2; i<=n; i++) { fibnminus2 = fibnminus1; 2 3 3 5 + + 5 8 4 5 fibnminus1 = fibn; fibn = fibnminus1 + fibnminus2; Složitost: 3*n return fibn; 1 1 1 1 1 2 + 3 Ing. Miroslav Balík, Ph.D. - BI-PA1-06 22/28 + 1 2 i 2 3

Složitost výpočtu Fibonacciho čísla Iterační metoda: 3*n Rekurzivní metoda: příklad pro fib(10): fib(10) fib(9) + fib(8) fib(8) + fib(7) fib(7) + fib(6) fib(7)+ fib(6) fib(6)+ fib(5) fib(6) + fib(5) fib(5) + fib(4) f 50 20 365 011 074 (20 miliard) Složitost je exponenciální!!!! int fib(int i) { if (i<2) return 1; return fib(i-1)+fib(i-2); Ing. Miroslav Balík, Ph.D. - BI-PA1-06 23/28

Složitost výpočtu Fibonacciho čísla 2 Iterační metoda: 3*n Rekurzivní výpočet ~ 2 n Přímý výpočet (Johannes Kepler) zlatý řez (golden ratio) 1,6180339887498948482045868343656 1 2 5, F( n) n 1 5 5 n Ing. Miroslav Balík, Ph.D. - BI-PA1-06 24/28

Příklad rekurze, základní schéma součin void main ( void ) { int x, y; ; printf ( %d %d, soui(x, y), sour(x,y)); int soui ( int s, int t ) { int i, si=0; for (i = 0; i < s; i++) si = si + t; int sour(int s, int t) { return si; int sr; if (s > 0) sr = sour(s - 1,t)+t; else sr = 0; return sr; Ing. Miroslav Balík, Ph.D. - BI-PA1-06 25/28 pro zájemce

Rozklad na prvočinitele Rozklad přirozeného čísla n na součin prvočísel Řešení: dělit 2, pak 3, atd., a dalšími prvočísly, n-1 každé dělení beze zbytku dodá jednoho prvočinitele Příklad: 60/2=>30/2=>15/3=>5/5 60 má prvočinitele 2, 2, 3, 5 Ing. Miroslav Balík, Ph.D. - BI-PA1-06 pro zájemce 26/28

Rozklad na prvočinitele - iterací int rozklad (int x, int d) { while (d < x && x % d!= 0) d++; printf ("%d \n",d); return d; void main (void ) { int x; int d = 2; printf ( zadejte prirozene cislo:\n"); scanf ("%d ",&x); if (x < 1) { printf ( cislo neni prirozene\n"); return; while (d < x) { d = rozklad(x, d); zadejte přirozené číslo: 144 x = x/d; 2 2 2 2 3 Ing. Miroslav Balík, Ph.D. - BI-PA1-06 pro zájemce 27/28

Rozklad na prvočinitele - rekurzí void rozklad (int x, int d ) { if (d < x) { while (d < x && x % d!= 0) d++; printf ("%d ",d); rozklad (x / d, d); void main(void) { int x; printf ( zadejte prirozene cislo:\n"); scanf ("%d ",&x) if (x < 1) { printf ( cislo neni prirozene\n"); return; rozklad(x, 2); zadejte přirozené číslo: 144 2 2 2 2 3 Ing. Miroslav Balík, Ph.D. - BI-PA1-06 pro zájemce 28/28