1 AAO folytatás ++ Csink László
2 Rekurzív bináris keresés (rendezett tömbben) public static int binker(int[] tomb, int value, int low, int high) public static int binker(int[] tomb, int value, int low, int high) { if (high < low) return -1; if (high < low) return -1; int mid = (low + high) / 2; int mid = (low + high) / 2; if (tomb[mid] > value) { if (tomb[mid] > value) { mid--; mid--; return binker(tomb, value, low, mid); return binker(tomb, value, low, mid); } else if (tomb[mid] < value) { else if (tomb[mid] < value) { mid++; mid++; return binker(tomb, value, mid, high); return binker(tomb, value, mid, high); } else return mid; else return mid; }
3 Iteratív bináris keresés (rendezett tömbben) public static int binker(int[] tomb, int value) { int mid, low = 0, high = tomb.Length-1; int mid, low = 0, high = tomb.Length-1; while (low <= high) { while (low <= high) { mid = (low + high) / 2; mid = (low + high) / 2; if (tomb[mid] > value) high = --mid; if (tomb[mid] > value) high = --mid; else if (tomb[mid] < value) low = ++mid; else if (tomb[mid] < value) low = ++mid; else return mid; // megtalálva else return mid; // megtalálva } return -1; // nincs meg return -1; // nincs meg }
4 Dinamikus Programozás
5 Mátrixok láncszorzása A dinamikus programozás egy általános eljárás bizonyos problémák megoldására Példa: Mátrixok láncszorzása Hogyan szorzunk mátrixokat. C = AB A is d × e, B is e × f O(d*e*f ) időben AC B dd f e f e i j i,j
6 Mátrixok láncszorzása Kiszámítandó A = A 0 A 1 …A n-1 A i mérete d i × d i+1 Probléma: Hogyan zárójelezzünk? Az eredménynek mindegy, mert a szorzás asszociatív, de a műveleti sebesség nagyon eltérhet! Example B mérete 3 × 100 C mérete 100 × 7 D mérete 7 × 5 (BC)D3 × 100 × ×7× 5 = 2305 szorzás B(CD)3 × 100 × × 7 × 5 = 5000 szorzás
7 A „brutális” módszer Mátrix láncszorzás: Próbáljuk megkeresni az összes zárójelezését A=A 0 A 1 …A n-1 -nak Mindegyikre számítsuk ki a műveletek számát Válasszuk ki a legjobbat Futásidő: Zárójeléezések száma = n-csúcsú bináris fák száma Exponenciális! Ez az n-dik Catalan szám – nagyságrendileg 4 n. Kiszámíthatatlan !
8 A mohó megközelítés Ötlet #1: mindig azt a szorzatot válasszuk, amelyik a legkevesebb műveletet igényli Ellenpélda arra, hogy a fenti ötlet optimális lehetne: A mérete 101 × 11 B mérete 11 × 9 C mérete 9 × 100 D mérete 100 × 99 Az ötlet szerint legjobb A((BC)D) = szorzás = szorzás Ennél jobb: (AB)(CD) = szorzás = szorzás AB 101*11*9=9999 BC 11*9*100=9900 CD 9*100*99=89100 A(BC) 101*11*100= (BC)D 11*100*99=108900
9 A “rekurzív” megközelítés Definiálunk alproblémákat: Keressük meg a legjobb zárójelezését ennek: A i A i+1 …A j. Legyen N i,j = ezen részprobléma műveleti igénye. A teljes probléma optimális megoldása N 0,n-1. Részprobléma optimalitás: Az optimális megoldás az optimális részprblémák függvényében lesz definiálva Kell, hogy legyen egy utoljára végrehajtott szorzás az optimális megoldásban (ez a bináris fa gyökere) Mondjuk, hogy ez az i indexnél volt: (A 0 …A i )(A i+1 …A n-1 ). Ekkor az optimális megoldás N 0,n-1 ia két optimális részmegoldás, N 0,i és N i+1,n-1 összege, valamint az utolsó szorzás
10 A karakterisztikus egyenlet A globális optimum az optimális részproblémáktól, valamint az utolsó szorzás helyétől függ Vizsgáljunk meg minden lehetséges helyet az utolsó szorzásra: Tudjuk, hogy A i mérete d i × d i+1 Így a karakterisztikus egyenlet N i,j –re a következő alakú: Az alproblémák nem függetlenek, az alproblémák átfedik egymást.
11 A dinamikus programozási algoritmus Nem használunk rekurziót, mivel az alproblémák átfedik egymást helyette “bottom-up” módon alproblémákkal foglalkozunk N i,i számítása könnyű, ezért ezzel kezdünk Ezután 2,3,… hosszú alproblémákkal foglalkozunk A futási idő: O(n 3 ) Algorithm matrixChain(S): Input: n db összeszorzandó mátrix Output:a szorzások optimális száma for i 1 to n-1 do N i,i 0 for b 1 to n-1 do for i 0 to n-b-1 do j i+b N i,j + for k i to j-1 do N i,j min{N i,j, N i,k +N k+1,j +d i d k+1 d j+1 }
12 A válasz N … n-1 … j i Az algoritmus magyarázata A bottom-up konstrukció feltölti az N tömböt az átlók mentén N i,j az i-dik sor és a j-dik oszlop korábban kiszámított értékeiből számítódik A táblázat egy eleme O(n) idő alatt tölthető ki A teljes idő O(n 3 ) A zárójelezéshez az kell, hogy „k” értékére „emlékezzünk” mindegyik esetben
13 A láncszorzási algoritmus Algorithm matrixChain(S): Input: n db összeszorzandó mátrix Output:# szorzások optimális száma for i 0 to n-1 do N i,i 0 for b 1 to n-1 do // b is # of ops in S for i 0 to n-b-1 do j i+b N i,j +infinity for k i to j-1 do sum = N i,k +N k+1,j +d i d k+1 d j+1 if (sum < N i,j ) then N i,j sum O i,j k return N 0,n-1 Példa: ABCD A mérete 10 × 5 B mérete 5 × 10 C mérete 10 × 5 D mérete 5 × 10 N A B C D AB BC CD A(BC) (BC)D (A(BC))D
14 static void Main(string[] args) { int[] d = { 10, 5, 10, 5, 10 }; int i, j, k, b, n = d.Length-1; int[] d = { 10, 5, 10, 5, 10 }; int i, j, k, b, n = d.Length-1; double sum = 0.0; const double v = 1.0 / 0; // végtelen double sum = 0.0; const double v = 1.0 / 0; // végtelen double[,] N = new double[n, n]; double[,] N = new double[n, n]; for(i=0;i<n;i++) N[i,i] = 0; for(i=0;i<n;i++) N[i,i] = 0; for(b=1;b<n;b++) for(b=1;b<n;b++) for (i = 0; i < n - b ; i++) { for (i = 0; i < n - b ; i++) { j = i + b; j = i + b; N[i,j] = v; // végtelen N[i,j] = v; // végtelen for (k = i; k < j ; k++) { for (k = i; k < j ; k++) { sum = N[i, k] + N[k + 1, j] + d[i] * d[k + 1] * d[j + 1]; sum = N[i, k] + N[k + 1, j] + d[i] * d[k + 1] * d[j + 1]; if (sum < N[i, j]) N[i, j] = sum; if (sum < N[i, j]) N[i, j] = sum; } } for (i = 0; i < n; i++) { for (i = 0; i < n; i++) { for (j = 0; j < n; j++) Console.Write(N[i, j].ToString().PadLeft(6) ); for (j = 0; j < n; j++) Console.Write(N[i, j].ToString().PadLeft(6) ); Console.WriteLine(); Console.WriteLine(); } Console.WriteLine("Az eredmény= " + N[0, n - 1]); Console.WriteLine("Az eredmény= " + N[0, n - 1]); Console.ReadLine(); Console.ReadLine(); } // Main vége
15 Recovering operations Example: ABCD A is 10 × 5 B is 5 × 10 C is 10 × 5 D is 5 × 10 N A B C D AB BC CD A(BC) (BC)D (A(BC))D // a zárójelezéshez // mátrixlánc A i -től A j -ig exp(i,j) if (i=j) then// alapeset, 1 mátrix return ‘A i ’ else k = O[i,j]// piros értékek S1 = exp(i,k)// 2 rekurzív hívás S2 = exp(k+1,j) return ‘(‘ S1 S2 ‘)’
16 static string EXP(int i, int j, int[,] O) { int k; string s1, s2; if (i == j) return "A" + i.ToString(); else { k = O[i, j]; s1 = EXP(i, k, O); s2 = EXP(k+1,j,O); return "("+s1 + s2+")"; static void Main(string[] args) { int[,] O = new int[n, n]; for(i=0;i<n;i++) N[i,i] = 0; for(b=1;b<n;b++) for (i = 0; i < n - b ; i++) { j = i + b; N[i,j] = v; for (k = i; k < j ; k++) { sum = N[i, k] + N[k + 1, j] + d[i] * d[k + 1] * d[j + 1]; if (sum < N[i, j]) { N[i, j] = sum; O[i, j] = k; } } Console.WriteLine("Az eredmény= " + N[0, n - 1]); Console.WriteLine("A zárójelezés = " + EXP(0,n-1,O)); Console.ReadLine(); } // Main vége
17 Optimalizálási problémák Egy optimalizálási problémában nemcsak egy megoldást, hanem a legjobb megoldást keressük A mohó algoritmus fázisokban dolgozik. Minden egyes fázisban: Tegyük azt, ami most a legjobb, nem törődve a jövővel. Abban bízik a mohó, hogy a lokális optimumok sorozata globális optimumhoz vezet. (Néha ez a helyzet, lásd Kruskal algoritmus, PPT, jövő félév).
18 Mohó algoritmusok Maximalizáljuk életünk örömeit: Első algoritmus: élvezzük az életet naponta Második algoritmus: dolgozz keményen, tanulj, szerezz diplomát, legyen jó fizetésű állásod, keress pénzt, és legyen jó nyugdíjad Melyik algoritmus maximalizál a teljes életre?