Γιάννης Σταματίου Μη αποδοτική αναδρομή και η δυναμική προσέγγιση Webcast 8
Περι αλγορίθμων, εν συντομία! Είδαμε (Webcast 1) ότι οι αλγόριθμοι χωρίζονται στις εξής κατηγορίες (σε σχέση με την πολυπλοκότητα χειρότερης περίπτωσης): Αποδοτικοί ή πολυωνυμικού χρόνου: O(n k ) Μη αποδοτικοί (intractable): O(k n ), O(n n ), O(n!) Τεχνικές για αποδοτικούς αλγόριθμους «Διαίρει και βασίλευε» (Divide and Conquer) Quick Sort, διαδική αναζήτηση, merge sort Η δυναμική προσέγγιση Όπου δεν «πίπτει» το «διαίρει και βασίλευε»! Δεν είναι δυνατή η υποδιαίρεση σε αρκούντως μικρά υποπροβλήματα
Αριθμοί Fibonacci int fib(int n) { if (n < 2) return n; else return (fib(n-1) + fib(n-2)) ; } Κομψό και εύκολο στην κατανόηση!
Ανάλυση Εάν ο αριθμός βημάτων υπολογισμού του αριθμού Fibonacci f n είναι t n τότε t n = t n-1 + t n-2 Καθώς είναι γνωστοί οι δύο πρώτοι όροι, ισχύει t 1 = t 2 = c Συνεπώς, t n = c’f n-2
Και λίγα διακριτά μαθηματικά... Συνεπώς και, άρα, ΕΚΘΕΤΙΚΟΣ ΧΡΟΝΟΣ, ΜΗ ΑΠΟΔΟΤΙΚΟΣ ΑΛΓΟΡΙΘΜΟΣ! lim n f n+1 fnfn = = f n+1 = O( n )
Η δυναμική προσέγγιση int fib( int n ) { int f1, f2, f; if ( n < 2 ) return n; else { f1 = f2 = 1; for( k = 2; k < n; k++ ) { f = f1 + f2; f2 = f1; f1 = f; } return f; }
int fib( int n ) { int f1, f2, f; if ( n < 2 ) return n; else { f1 = f2 = 1; for( k = 2; k < n; k++ ) { f = f1 + f2; f2 = f1; f1 = f; } return f; } Λύνουμε μικρά υποπροβλήματα πρώτα! Και στη συνέχεια λύνουμε το μεγαλύτερο πρόβλημα! Σε κάθε βήμα, ο αλγόριθμος θυμάται τη λύση των δύο πιο πρόσφατων υποπροβλημάτων.
Η γενική δυναμική προσέγγιση Λύνουμε πρώτα μικρά υποπροβλήματα Αποθηκεύουμε τις λύσεις τους Χρησιμοποιούμε τις λύσεις στα μικρότερα προβλήματα για να λύσουμε τα μεγαλύτερα Στην περίπτωση των αριθμών Fibonacci, ο χρόνος επίλυσης μειώνεται δραματικά σε O(n) από O(1.618 n )