Rozklad problému na podproblémy, rekurze

Slides:



Advertisements
Podobné prezentace
Programování v C jazyku - SEMINÁŘ
Advertisements

Spojové struktury Spojová struktura ( linked structure ):
PA081 Programování numerických výpočtů
Metody (funkce, procedury)
ALGO – Algoritmizace 1. cvičení
Třídění Seminář IVT. Definice uspořádání skupiny dat (záznamů) dle daného klíče vzestupně (od nejmenší do největší hodnoty klíče) sestupně (od největší.
Alg51 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ů.
Cvičení 2 Proměnné(jednoduché a složené) a konstanty První program Zápis výrazů.
If-else, do-while, switch, operátory
Algoritmy I Cvičení č. 3.
Medians and Order Statistics Nechť A je množina obsahující n různých prvků: Definice: Statistika i-tého řádu je i-tý nejmenší prvek, tj., minimum = statistika.
Větvení cykly J a v a Začínáme programovat Lucie Žoltá.
Struktury, qsort, mergesort BI-PA1 Programování a algoritmizace 1, ZS Katedra teoretické informatiky © Miroslav Balík Fakulta informačních technologií.
Algoritmizace a programování
Algoritmizace a programování Podmíněné a cyklické příkazy- 08
Informatika I 2. přednáška
C – strukturované příkazy
Gramatiky a jazyky Přednáška z předmětu Řízení v komplexních systémech
Časová složitost algoritmů, řazení a vyhledávání
Algoritmizace a programování Třídící algoritmy - 12
Časová složitost algoritmů
Ukázka odstranění rekurze Přemysl Tišer
Počítače a programování 1
JavaScript Podmínky, cykly a pole.
Cvičení.
5. Procedury a funkce Procedura je samostatně odladěný algoritmus, v programu může být volána vícekrát. Dvojí terminologie - rozlišujeme procedury a funkce.
Informatika I 7. přednáška RNDr. Jiří Dvořák, CSc.
Informatika I 8. přednáška RNDr. Jiří Dvořák, CSc.
Příklady v jazyku C – část 4
2 CYKLUS S PEVNÝM POČTEM OPAKOVÁNÍ Podle řídící proměnné proveď n-krát příkaz P1.
Příklady v jazyku C – část 3
Spojové struktury BI-PA1 Programování a algoritmizace 1, ZS
7. Typ soubor Souborem dat běžně rozumíme uspořádanou množinu dat, uloženou mimo operační paměť počítače (na disku). Pascalský soubor je abstrakcí skutečného.
Napište program v C pro výpočet plochy obdélníka se stranami A=3 a B=2. Výsledek vytiskněte s patřičným komentářem na obrazovku formátovým příkazem printf.
OSNOVA: a)Funkce – úvod b) Hlavičky funkcí c) Rekurze funkcí d)Knihovny funkcí e)Příklady Jiří Šebesta Ústav radioelektroniky, FEKT VUT v Brně Počítače.
Realloc a qsort examples BI-PA1 Programování a algoritmizace 1 Katedra teoretické informatiky © Miroslav Balík Fakulta informačních technologií České vysoké.
A1PRG - Programování – Seminář Ing. Michal Řízení běhu programu 5 Verze
Ukazatele BI-PA1 Programování a algoritmizace 1, ZS Katedra teoretické informatiky © Miroslav Balík Fakulta informačních technologií České vysoké.
Cykly Cykly umožňují provádět určitou část kódu opakovaně až do nastaveného počtu cyklování nebo splnění podmínky. Cykly umožňují provádět určitou část.
C – jak na procedury Mgr. Lenka Švancarová. C – procedury #include int main() { printf("Ahoj\n"); return(0); } #include void pozdrav(void) { printf("Ahoj\n");
Příklady v jazyku C – část 8. Napište program, který inicializuje 2-rozměrné pole uživatele (5 řádků, 2 sloupce) a naplní ho hodnotami (první sloupec.
Soubory BI-PA1 Programování a algoritmizace 1, ZS Katedra teoretické informatiky © Miroslav Balík Fakulta informačních technologií České vysoké.
Jazyk C A0B36PRI - PROGRAMOVÁNÍ Část II.
Jazyk C A0B36PRI - PROGRAMOVÁNÍ Část I.
C – procedury Mgr. Lenka Švancarová.
Sylabus V rámci PNV budeme řešit konkrétní úlohy a to z následujících oblastí: Nelineární úlohy Řešení nelineárních rovnic Numerická integrace Lineární.
C – if Mgr. Lenka Švancarová. if vývojový diagram Podmínka Příkaz(y) Podmínka Příkaz(y) Úplné větveníNeúplné větvení ++--
C – cyklus do-while Mgr. Lenka Švancarová.
Rekurze. volání podprogramu opětovně v jeho těle –v době, kdy předchozí volání ještě nebylo ukončeno Druhy rekurze přímá rekurze nepřímá rekurze.
Funkce, intuitivní chápání složitosti
Funkce Přednáška č. 5. Funkce (functions)  posloupnost příkazů uvedená hlavičkou  využití – opakovaně volaná sekvence – strukturování programu – ošetření.
Procedurální programování,
Algoritmizace a programování Algoritmy 4 – Vývojové diagramy (cykly)
Algoritmizace a programování Algoritmy 1 - Úvod. Základní pojmy Počítačový program Počítačový program zápis zdrojového kódu, kterému rozumí počítač zápis.
M2160 – Úvod do programování II
Programování ENUM, SWITCH,pole jednorozměrná a vícerozměrná, deklarace, inicializace, kopírování, porovnání Erik Král.
Rekurze.
C# konzole – Podíl dvou čísel, podmínka IF
Výukový materiál zpracován v rámci projektu
Vytváření dokumentace algoritmů
Rekurze.
Příkazy cyklu (1) Umožňují vícekrát (nebo ani jednou) pro-vést určitý příkaz Jazyk C rozlišuje příkaz cyklu: s podmínkou na začátku: obecný tvar: while.
© Copyright Radim Štefan
Opakování základních příkazů a syntaxí v programovacím jazyce Pascal
Podprogramy.
Opakování ze 3. cvičení deklarace proměnných výpis na monitor (výstup)
Cyklus for (1) Obecný tvar: for (výraz1; výraz2; výraz3) příkaz
Algoritmizace Dynamické programování
Opakování ze 4. cvičení int a; printf("Zadej číslo: ");
Algoritmizace a datové struktury (14ASD)
Transkript prezentace:

Rozklad problému na podproblémy, rekurze PA1 - 02 Rozklad problému na podproblémy, rekurze BI-PA1 Programování a algoritmizace 1 Fakulta informačních technologií České vysoké učení technické PA1-6 ALG

Rozklad problému na podproblémy PA1 - 02 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 PA1-6 ALG

v hrubém řešení použijeme typ bool, jehož hodnotami jsou true a false PA1 - 02 Hra NIM Hrubé řešení: int pocet; bool stroj = false; “zadání počtu zápalek“ do { if (stroj) “odebrání zápalek strojem“ else “odebrání zápalek hráčem“ stroj = !stroj; } while (pocet > 0); if (stroj) “vyhrál stroj“ 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 v hrubém řešení použijeme typ bool, jehož hodnotami jsou true a false PA1-6 ALG

Vysvětlení na dalším slajdu PA1 - 02 Hra NIM /* prog6-nim.c */ #include <stdio.h> #include <stdlib.h> #define bool char #define true 1 #define false 0 int pocet; 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; chyba = false; printf("pocet zapalek je %d\n", pocet); printf("kolik odeberete: "); scanf("%d", &x); co je typ bool ? co je to false ? Vysvětlení na dalším slajdu PA1-6 ALG

PA1 - 02 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"); system("PAUSE"); return 0; PA1-6 ALG

PA1 - 02 Direktiva define /* prog6-nim.c */ #define bool char #define true 1 #define false 0 int pocet; bool stroj = false; takže překladač zpracuje deklaraci proměnné stroj takto char stroj = 0; 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 PA1-6 ALG

PA1 - 02 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; } PA1-6 ALG

Rekurze Definice ze slovníku (pozor vtip) Rekurze viz „Rekurze“ PA1 - 02 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)! PA1-6 ALG

Faktoriál pomocí rekurze a iterace PA1 - 02 Faktoriál pomocí rekurze a iterace n! = 1 pro n1 n! = n*(n-1)! pro n>1 int fakt(int n) { if (n<=1) return 1; return n*fakt(n-1); } int fakt(int n) { if (n<=1) return 1; else return n*fakt(n-1); } int fakt(int n) { int f = 1; while (n>1){ f *= n; n--; } return f; } int fakt(int n) { return n<=1?1:n*fakt(n-1); // ternární operátor } PA1-6 ALG

Iterační alg. – NSD(), připomenutí PA1 - 02 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; Platí: Je-li x  y (> 0), pak x mod y < x/2 (55 88, 88 55, 55 33, 33 22, 22 11, 11 11, 11 0) Důkaz: buď je y  x/2 nebo je y > x/2 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.log2 n průchodech. Kolikrát se provede tělo cyklu while ? y x / 2 y x y x mod y x / 2 y x x mod y y PA1-6 ALG

Rekurzivní algoritmus – NSD() I PA1 - 02 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 static int nsd(int x, int y) { int zbytek; while( y != 0 ) { zbytek = x % y; x = y; y = zbytek; } return x; Iterace PA1-6 ALG

Rekurze a rozklad problému na podproblémy PA1 - 02 Rekurze a rozklad problému na podproblémy Příklad: 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é”) PA1-6 ALG

Příklad rekurze „Obrať posloupnost“ PA1 - 02 Příklad rekurze „Obrať posloupnost“ „obrať posloupnost“ přečti číslo if (přečtené číslo není nula) „obrať posloupnost, tj. zbytek“ vypiš číslo 2 cti x 4 if()… cti x 6 if()… cti x 8 if()… 2 4 6 8 0 0 8 6 4 2 cti x if()… cti x if()… 8 6 piš x 4 piš x piš x 2 piš x piš x PA1-6 ALG

Příklad rekurze - obrat() PA1 - 02 Příklad rekurze - obrat() /* prog6-obrat.c */ #include <stdio.h> #include <stdlib.h> 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; PA1-6 ALG

Příklad rekurze - Hanojské věže PA1 - 02 Příklad rekurze - Hanojské věže Ú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ší. 1 2 3 PA1-6 ALG

Příklad rekurze - Hanojské věže PA1 - 02 Příklad rekurze - Hanojské věže 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) 1 2 3 PA1-6 ALG

Hanojské věže /* prog6-hanoj.c */ /* hanojske veze */ PA1 - 02 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; PA1-6 ALG

Příklad rekurze - Hanojské věže PA1 - 02 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) { prenesVez(vyska-1, odkud, pomoci, kam); printf("prenes disk z %d na %d\n", odkud, kam); prenesVez(vyska-1, pomoci, kam, odkud); } 3 přenes disk z 1 na 2 přenes disk z 1 na 3 přenes disk z 2 na 3 přenes disk z 3 na 1 přenes disk z 3 na 2 PA1-6 ALG

PA1 - 02 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 PA1-6 ALG

Fibonacciho posloupnost - historie PA1 - 02 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 ….. 12 144 50 20 365 011 074 (20 miliard) počet krav = počet krav vloni + počet narozených (odpovídá počtu krav předloni) fn = fn-1 + fn-2 PA1-6 ALG

Fibonacciho posloupnost PA1 - 02 Fibonacciho posloupnost Platí: f0 = 1 f1 = 1 fn = fn-1 + fn-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í? PA1-6 ALG

Fibonacciho posloupnost - iteračně PA1 - 02 Fibonacciho posloupnost - iteračně Platí: f0 = 1 f1 = 1 fn = fn-1 + fn-2 ,pro n > 1 Iteračně: int fib(int n) { int i, fibNMinus2=1; int fibNMinus1=1, fibN=1; for (i=2; i<=n; i++) { fibNMinus2 = fibNMinus1; fibNMinus1 = fibN; fibN = fibNMinus1 + fibNMinus2; } return fibN; fibNMinus2 fibNMinu1 fibN i 1 1 1 1 1 + 2 2 1 2 + 3 3 2 3 + 5 4 3 5 + 8 5 Složitost: 3*n PA1-6 ALG

Složitost výpočtu Fibonacciho čísla PA1 - 02 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(5) + fib(4) fib(6) + fib(5) f50 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); } PA1-6 ALG

Složitost výpočtu Fibonacciho čísla 2 PA1 - 02 Složitost výpočtu Fibonacciho čísla 2 Iterační metoda: 3*n Rekurzivní výpočet ~ 2n Přímý výpočet (Johannes Kepler) zlatý řez (golden ratio) ≈1,6180339887498948482045868343656 PA1-6 ALG

Příklad rekurze, základní schéma – součin PA1 - 02 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 souI=0; for (int i = 0; i < s; i++) souI=souI+t; return souI; int souR(int s, int t) { int souR; if (s > 0)souR=souR(s - 1,t)+t; else souR = 0; return souR; } PA1-6 pro zájemce ALG

Rozklad na prvočinitele PA1 - 02 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 PA1-6 pro zájemce ALG

Rozklad na prvočinitele - iterací PA1 - 02 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; printf("zadejte přirozené číslo: \n"); scanf(“%d”,&x); if (x < 1) { printf("číslo není přirozené"); return; int d = 2; while (d < x) { d = rozklad(x, d); x = x/d; zadejte přirozené číslo: 144 2 2 2 2 3 PA1-6 pro zájemce ALG

Rozklad na prvočinitele - rekurzí PA1 - 02 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 přirozené číslo: \n"); scanf(“%d”,&x) if (x < 1) { printf("číslo není přirozené"); return; rozklad(x, 2); zadejte přirozené číslo: 144 2 2 2 2 3 PA1-6 pro zájemce ALG