Δυναμικός προγραμματισμός.

2
Τμήμα Ηλεκτρονικών Μηχ. & Μηχ. Υπολογιστών
ΣΕΛ 402: Παράλληλοι Αλγόριθμοι και Software
Δυναμικός Προγραμματισμός
Φθινόπωρο 2001
Διδάσκων: Τάσος Δημητρίου
Δυναμικός Προγραμματισμός
είχε υπολογιστεί προηγουμένως με αποτέλεσμα να εκτελεί περιττή δουλειά. Αν όμως φυλάγαμε τα
αποτελέσματα σε ένα πίνακα και τα ανακαλούσαμε όποτε τα χρειαζόμαστε, το αποτέλεσμα θα ήταν
ένας αποτελεσματικός αλγόριθμος. Και αυτός ο αλγόριθμος ήταν ο δεύτερος που είχαμε σχεδιάσει, ο
οποίος αποτελούσε παράδειγμα δυναμικού προγραμματισμού.
Χαρακτηριστικά Δυναμικού Προγραμματισμού
Εισαγωγικά
Ο Δυναμικός Προγραμματισμός (Dynamic Programming), όπως και η μέθοδος Divide and Conquer,
είναι μία γενική μέθοδος επίλυσης προβλημάτων η οποία βασίζεται στο συνδυασμό λύσεων επιμέρους
υποπροβλημάτων του αρχικού προβλήματος. Η λέξη \Προγραμματισμός" αναφέρεται στο γεγονός ότι
η μέθοδος βασίζεται στην προσθήκη τιμών, με κάποιο συστηματικό τρόπο, σε ένα κατάλληλα ορισμένο
πίνακα.
Οι αλγόριθμοι Divide and Conquer διαμερίζουν το πρόβλημα σε ανεξάρτητα υποπροβλήματα, τα
επιλύουν αναδρομικά και στη συνέχεια συνδυάζουν τις λύσεις για να λύσουν το αρχικό πρόβλημα.
Αντίθετα, ο Δυναμικός Προγραμματισμός εφαρμόζεται όταν τα υποπροβλήματα δεν είναι ανεξάρτητα.
Ο αλγόριθμος λύνει κάθε υποπρόβλημα χωριστά και στη συνέχεια φυλάει τις απαντήσεις σε έναν
πίνακα, ώστε να είναι έτοιμες να ξαναχρησιμοποιηθούν αν το συγκεκριμένο υποπρόβλημα εμφανιστεί
ξανά.
Ας προσπαθήσουμε να εξηγήσουμε τις παραπάνω παρατηρήσεις με δύο παραδείγματα. Θεωρείστε
ξανά μία τυπική σχέση Divide and Conquer σχέση
n
T (n) = aT ( ) + O(nc );
b
στην οποία κάθε στιγμιότυπο μεγέθους n σπάει σε a στιγμιότυπα μεγέθους n=b. Το κόστος συνδυασμού
των επιμέρους λύσεων είναι πολυωνυμικό, τάξης O(nc ). Γιατί ο τελικός αλγόριθμος είναι πολυωνυμικός;
Η απάντηση είναι επειδή ο συνολικός χρόνος φράσσεται από το γινόμενο του συνολικού αριθμού
υποπροβλημάτων επί το μέγιστο κόστος συνδυασμού των λύσεων τους. Και επειδή ο αριθμός των
υποπροβλημάτων είναι πολυωνυμικός και το κόστος επικόλλησης είναι O(nc ), ο αλγόριθμος δουλεύει
σε πολυωνυμικό χρόνο. Θεωρείστε για παράδειγμα τη σχέση T (n) = 2T (n=2) + O(nc ). Στο
τελευταίο επίπεδο της αναδρομής υπάρχουν n υποπροβλήματα μεγέθους 1. Στο προτελευταίο, n=2
υποπροβλήματα μεγέθους 2, κοκ. Άρα ο συνολικός αριθμός υποπροβλημάτων είναι n + n=2 + n=4 +
¢ ¢ ¢ + 1 ∙ 2n. Το ίδιο ισχύει και για πιο γενικές αναδρομικές σχέσεις. Πολλαπλασιάζοντας τον αριθμό
των υποπροβλημάτων με το κόστος συνδυασμού των λύσεων προκύπτει το ζητούμενο.
Ας πάμε τώρα πίσω μερικές διαλέξεις στον πρώτο αλγόριθμο υπολογισμού των αριθμών Fibonacci,
ο οποίος φαίνεται παρακάτω.
Fib(n)
if n = 0 then return 0
if n = 1 then return 1
return Fib(n ¡ 1) + Fib(n ¡ 2)
Ο δυναμικός προγραμματισμός εφαρμόζεται κυρίως σε προβλήματα βελτιστοποίησης. Σε ένα τέτοιο
πρόβλημα μπορεί να υπάρχουν πολλές λύσεις. Κάθε λύση έχει μία τιμή και μας ενδιαφέρει να βρούμε
τη λύση με τη βέλτιστη τιμή. Μία τέτοια λύση την ονομάζουμε βέλτιστη. Για παράδειγμα, θεωρείστε
ότι μας δίνεται ένας χάρτης, μια πόλη A και μας ζητείται να βρούμε τις διαδρομές με τη μικρότερη
απόσταση από την A προς όλες τις άλλες τις πόλεις του χάρτη. Ως λύσεις θα μπορούσαν να θεωρηθούν
οι διάφορες εναλλακτικές διαδρομές, αλλά ως βέλτιστη θα ήταν εκείνη η λύση στην οποία όλες οι
διαδρομές θα ήταν ελάχιστες.
Δοθέντος κάποιου τέτοιου προβλήματος πως θα ξέρουμε αν πρέπει να εφαρμόσουμε ή όχι δυναμικό
προγραμματισμό; Ποιες ιδιότητες θα πρέπει να αναζητούμε για την εφαρμογή της μεθόδου; Η απάντηση
είναι οι δύο παρακάτω:
1. Βέλτιστη Υποδομή (Optimal Substructure)
Θα λέμε ότι ένα πρόβλημα παρουσιάζει βέλτιστη υποδομή αν η βέλτιστη λύση περιέχει βέλτιστες
λύσεις στα διάφορα υποπροβλήματα. Με άλλα λόγια αν η λύση κάποιου υποπροβλήματος δεν
είναι βέλτιστη τότε και η λύση στο αρχικό πρόβλημα δε θα είναι βέλτιστη.
Αυτή η παρατήρηση οδηγεί αυτόματα και σε μία τεχνική ελέγχου αν το πρόβλημα παρουσιάζει
Optimal Substructure. Ρωτάμε απλά τι γίνεται στην περίπτωση που η λύση κάποιου υποπροβλήματος δεν είναι βέλτιστη. Επηρεάζει αυτό την τελική λύση; Αν ναι, τότε υπάρχει βέλτιστη υποδομή.
Αν όχι, τότε μάλλον ο δυναμικός προγραμματισμός δεν είναι η κατάλληλη μέθοδος επίλυσης.
2. Κοινά Υποπροβλήματα
Ο αριθμός των υποπροβλημάτων πρέπει να είναι μικρός, δηλαδή πολυωνυμικός στο μέγεθος
της εισόδου. Ο αλγόριθμος συναντά τα ίδια υποπροβλήματα ξανά και ξανά (θυμηθείτε τους
Fibonacci αριθμούς) τα οποία λύνει μία φορά, αποθηκεύει τις λύσεις σε κάποιο πίνακα και στη
συνέχεια τις ανακαλεί με σταθερό κόστος για να συνθέσει τη γενική λύση.
Αντίθετα η τεχνική Divide and Conquer εφαρμόζεται όταν σε κάθε στάδιο του αλγόριθμου
δημιουργούνται νέα, διαφορετικά υποπροβλήματα.
Τα στάδια σχεδιασμού ενός αλγόριθμου με δυναμικό προγραμματισμό είναι τα παρακάτω:
1. Χαρακτηρισμός Βέλτιστης Λύσης
Συγκεκριμένα προσπαθούμε να απαντήσουμε αν η λύση εμφανίζει τις δύο παραπάνω ιδιότητες.
2. Αναδρομικός Ορισμός Λύσης
Ορίζεται η βέλτιστη λύση αναδρομικά χρησιμοποιώντας τις λύσεις των επιμέρους υποπροβλημάτων.
Σε αυτό τον ορισμό θα βασιστεί ο αλγόριθμος εύρεσης της λύσης.
Ο αλγόριθμος αυτός βασίζεται στην αναδρομική σχέση του ορισμού των αριθμών Fibonacci και
όπως είχαμε αναφέρει λειτουργούσε σε εκθετικό χρόνο. Ο λόγος ήταν επειδή για τον υπολογισμό του
F ib(n) έπρεπε να υπολογίσει τα F ib(n¡1) και F ib(n¡2). Για τον υπολογισμό του F ib(n¡1) έπρεπε
να υπολογίσει τα F ib(n ¡ 2) και F ib(n ¡ 3), κοκ. Ο αλγόριθμος δεν λάμβανε υπόψη ότι το F ib(n ¡ 2)
1
3. Υπολογισμός Βέλτιστης Λύσης
Χρησιμοποιώντας την ιδιότητα των κοινών υποπροβλημάτων σχεδιάζεται ένας αλγόριθμος που
αποθηκεύει τις μερικές λύσεις για να τις χρησιμοποιήσει στον υπολογισμό της τελικής λύσης,
σύμφωνα πάντα με τον παραπάνω αναδρομικό ορισμό.
Διδάσκων: Τάσος Δημητρίου
3
4
Δυναμικός Προγραμματισμός
Ας δούμε όμως ένα παράδειγμα εφαρμογής των παραπάνω παρατηρήσεων.
Πολλαπλασιασμός Ακολουθίας Πινάκων
M1
Θεωρείστε το πρόβλημα υπολογισμού του γινομένου n πινάκων
M4
M2
M1
M = M1 £ M2 £ ¢ ¢ ¢ £ Mn ;
όπου κάθε Mi είναι ένας πίνακας με ri¡1 γραμμές και ri στήλες. Η σειρά με την οποία γίνονται οι
πολλαπλασιασμοί των πινάκων μπορεί να έχει μεγάλο αντίκτυπο στο συνολικό αριθμό των πράξεων
που απαιτούνται για τον υπολογισμό του M .
Παράδειγμα 1 Ας θεωρήσουμε ότι το γινόμενο C ενός p £ q πίνακα A με ένα q £ r πίνακα B απαιτεί
pqr πολλαπλασιασμούς, όπως φαίνεται από τη σχέση
Για κάθε 1 ∙ i ∙ p και 1 ∙ j ∙ r;
Ci;j =
q
X
Ai;k Bk;j :
k=1
Θεωρείστε επίσης το γινόμενο 4 πινάκων των οποίων οι διαστάσεις φαίνονται μέσα σε αγγύλες.
M
=
M1
£
M2
£
M3
£
M4
[10 £ 20]
[20 £ 50]
[50 £ 1]
[1 £ 100]
Αν υπολογίσουμε το M σύμφωνα με την παρενθετοποίηση
M1 £ (M2 £ (M3 £ M4 ))
απαιτούνται 125000 πολλαπλασιασμοί, ενώ σύμφωνα με την
(M1 £ (M2 £ M3 )) £ M4
απαιτούνται μόνο 2200 πολλαπλασιασμοί. Φαίνεται λοιπόν ότι η σειρά των πράξεων παίζει σημαντικό
ρόλο στην αποτελεσματικότητα του αλγορίθμου.
Μήπως όμως μπορούμε απλά να απαριθμήσουμε όλες τις δυνατές παρενθετοποιήσεις και να βρούμε
την καλύτερη; Η απάντηση είναι όχι. Κάθε παρενθετοποίηση αντιστοιχεί σε ένα δυαδικό δέντρο του
οποίου τα φύλλα αντιστοιχούν στους πίνακες που θέλουμε να πολλαπλασιάσουμε, όπως φαίνεται και
στο Σχήμα 1.
Το δέντρο στο (α) αντιστοιχεί στην πρώτη παρενθετοποίηση του Παραδείγματος 1. Πρώτα πολλαπλασιάζονται οι M3 ; M4 , το αποτέλεσμά τους με το M2 και το νέο αποτέλεσμα ξανά με το M1 .
Αντίστοιχα ισχύουν και για το δέντρο στο (β). Αποδεικνύεται λοιπόν ότι οι δυνατές παρενθετοποιήσεις
βρίσκονται σε 1-1 αντιστοιχία με τα δυαδικά δέντρα της παραπάνω μορφής. Όμως ο αριθμός των
δυνατών δέντρων είναι τάξης ­(4n =n1:5 ), μια εκθετικά μεγάλη ποσότητα, κάτι που αποκλείει την
απαρίθμηση. Θα δούμε όμως ότι με δυναμικό προγραμματισμό τα πράγματα βελτιώνονται σημαντικά.
M3
M4
M2
(α)
M3
(β)
Σχήμα 1: Δέντρα Πολλαπλασιασμού Πινάκων
Χαρακτηρισμός Βέλτιστης Λύσης
Ας δούμε πρώτα αν η βέλτιστη λύση παρουσιάζει optimal υποδομή. Θα χρησιμοποιήσουμε το συμβολισμό Mi;j για τον πίνακα που προκύπτει από τον πολλαπλασιασμό
Mi £ Mi+1 £ ¢ ¢ ¢ £ Mj :
Η καλύτερη παρενθετοποίηση του γινομένου M1 £ M2 £ ¢ ¢ ¢ £ Mn θα πρέπει να το χωρίζει σε δύο
γινόμενα
M1;k = M1 £ M2 £ ¢ ¢ ¢ £ Mk και Mk+1;n = Mk+1 £ Mk+2 £ ¢ ¢ ¢ £ Mn
για κάποιο k, με 1 ∙ k < n. Με άλλα λόγια, για κάποιο k, το οποίο δεν ξέρουμε αλλά γνωρίζουμε ότι
υπάρχει, πρώτα υπολογίζουμε τους πίνακες M1;k και Mk+1;n και στη συνέχεια τους πολλαπλασιάζουμε
για να βρούμε το τελικό πίνακα. Άρα το κόστος της βέλτιστης παρενθετοποίησης του M είναι το
κόστος υπολογισμού (παρενθετοποίησης) του πίνακα M1;k , συν το κόστος υπολογισμού του Mk+1;n ,
συν το κόστος του πολλαπλασιασμού αυτών των δύο μεταξύ τους.
Η σημαντική παρατήρηση είναι ότι η παρενθετοποίηση καθενός από τα M1;k και Mk+1;n πρέπει
να είναι επίσης βέλτιστη. Αν υπήρχε ένας καλύτερος τρόπος να ομαδοποιηθεί (με παρενθέσεις) η
υπακολουθία M1 £ M2 £ ¢ ¢ ¢ £ Mk , αντικαθιστώντας τη νέα αυτή παρενθετοποίηση στη βέλτιστη
παρενθετοποίηση του M1 £ M2 £ ¢ ¢ ¢ £ Mn θα παίρναμε μία άλλη λύση της οποίας το κόστος θα ήταν
καλύτερο από αυτό της βέλτιστης λύσης. Άτοπο. Άρα η παρενθετοποίησης της M1 £ M2 £ ¢ ¢ ¢ £ Mk
θα πρέπει και αυτή να είναι βέλτιστη. Ανάλογα ισχύουν και για την υπακολουθία Mk+1;n = Mk+1 £
Mk+2 £ ¢ ¢ ¢ £ Mn . Συμπεραίνουμε λοιπόν ότι η βέλτιστη λύση σε ένα στιγμιότυπο του προβλήματος
περιέχει βέλτιστες λύσεις σε υποπροβλήματα.
Αν προχωρήσουμε ένα ακόμη επίπεδο στην ανάλυσή μας θα δούμε ότι και η υπακολουθία M1 £
M2 £ ¢ ¢ ¢ £ Mk θα πρέπει να διασπαστεί σε δύο μέρη M1;l και Ml+1;k για κάποιο νέο δείκτη l, καθένα
από τα οποία θα πρέπει να παρενθετοποιηθεί με ένα βέλτιστο τρόπο. Ποιος είναι λοιπόν ο τύπος
των υποπροβλημάτων στα οποία θα εφαρμοστεί ο αλγόριθμος; Δεν είναι δύσκολο να δούμε ότι όλα
τα υποπροβλήματα αποτελούνται από υπακολουθίες του αρχικού προβλήματος M1 £ M2 £ ¢ ¢ ¢ £ Mn .
Έτσι, το σύνολο των ακολουθιών της μορφής Mi £ Mi+1 £ ¢ ¢ ¢ £ Mj , για 1 ∙ i; j ∙ n, αποτελεί το
χώρο των υποπροβλημάτων στον οποίο θα κινηθεί ο αλγόριθμος.
Γενικά, εξετάζοντας τη δομή των υποπροβλημάτων για την εμφάνιση ή όχι βέλτιστης υποδομής και
σ' αυτά, αποτελεί ένα καλό τρόπο για να συμπεράνουμε τη μορφή τους αλλά και τον αριθμό τους.
Διδάσκων: Τάσος Δημητρίου
5
Ποιο είναι τώρα το πλήθος των υποπροβλημάτων; Είναι της τάξης του O(n2 ), αφού υπάρχει ένα
υποπρόβλημα (εύρεση παρενθετοποίησης του) Mi;j = Mi £ Mi+1 £ ¢ ¢ ¢ £ Mj , για κάθε 1 ∙ i; j ∙ n.
Ενώ όπως είχαμε αναφέρει ο αριθμός των δυνατών λύσεων είναι εκθετικά μεγάλος, ο αριθμός των
υποπροβλημάτων είναι πολυωνυμικά μικρός. Αποθηκεύοντας λοιπόν τις λύσεις αυτών σε ένα πίνακα,
ο αλγόριθμος θα τις ανακαλεί με σταθερό κόστος ώστε να σχηματίσει τη βέλτιστη λύση.
Αναδρομικός Ορισμός Λύσης
Έχοντας ορίσει τον τύπο των υποπροβλημάτων είναι εύκολο να ορίσουμε αναδρομικά το κόστος της
βέλτιστης λύσης. Ας είναι λοιπόν mi;j ο ελάχιστος αριθμών πολλαπλασιασμών που απαιτούνται για
τον υπολογισμό (παρενθετοποίηση) του γινομένου Mi;j = Mi £ Mi+1 £ ¢ ¢ ¢ £ Mj . Προφανώς m1;n
θα είναι το κόστος πολλαπλασιασμού του αρχικού γινομένου κατά βέλτιστο τρόπο. Για να ορίσουμε
το mi;j αναδρομικά εξετάζουμε δύο περιπτώσεις:
1. i = j.
Αν i = j τότε η υπακολουθία Mi;i αποτελείται από ένα μόνο πίνακα, τον Mi , άρα δεν υπάρχει
τίποτε για να πολλαπλασιάσουμε. Επομένως, mi;i = 0, για i = 1; : : : ; n.
6
Δυναμικός Προγραμματισμός
MatrixProduct(M1 ; M2 ; : : : ; Mn )
begin
for i = 1 to n do mi;i = 0
for l = 1 to n ¡ 1 do
for i = 1 to n ¡ l do
begin
j = i+l
mi;j = mini∙k<j (mi;k + mk+1;j + ri¡1 rk rj )
end
Output m1;n
end
Ο χρόνος του αλγόριθμου είναι O(n3 ) και όχι O(n2 ) επειδή ο υπολογισμός του ελάχιστου k, i ∙ k < j,
συνεισφέρει έναν ακόμα O(n) παράγοντα.
Παράδειγμα 2 Εφαρμόζοντας τον αλγόριθμο για τους πίνακες του Παραδείγματος 1, όπου οι διαστάσεις
r0 ; r1 ; r2 ; r3 ; r4 είναι ίσες με 10; 20; 50; 1; 100, βρίσκουμε τον ακόλουθο πίνακα τιμών.
m14 = 2200
2. i 6
= j.
Για να υπολογίσουμε το mi;j όταν i < j, θα κάνουμε χρήση της ιδιότητας της βέλτιστης
υποδομής. Η καλύτερη παρενθετοποίηση του γινομένου Mi £ ¢ ¢ ¢ £ Mj θα πρέπει να το χωρίζει
σε δύο γινόμενα Mi;k = Mi £ ¢ ¢ ¢ £ Mk και Mk+1;j = Mk+1 £ ¢ ¢ ¢ £ Mj για κάποιο k, με
i ∙ k < j. Άρα το κόστος της βέλτιστης παρενθετοποίησης του Mi;j θα είναι το κόστος
υπολογισμού του πίνακα Mi;k , συν το κόστος υπολογισμού του Mk+1;j , συν το κόστος του
πολλαπλασιασμού αυτών των δύο μεταξύ τους. Εφόσον ο πολλαπλασιασμός των πινάκων Mi;k
και Mk+1;j απαιτεί ri¡1 rk rj πράξεις, καταλήγουμε στη σχέση
mi;j = mi;k + mk+1;j + ri¡1 rk rj :
m13 = 1200
m2;4 = 3000
m12 = 10000
m2;3 = 1000
m3;4 = 5000
m11 = 0
m2;2 = 0
m3;3 = 0
Ας δούμε χαρακτηριστικά πως προκύπτουν μερικές τιμές. Εφαρμόζοντας την αναδρομική σχέση (1)
έχουμε:
(
m1;1 + m2;3 + 10 ¢ 20 ¢ 1 = 1200
m1;3 = min
m1;2 + m3;3 + 10 ¢ 50 ¢ 1 = 10500
Ποια είναι όμως η κατάλληλη τιμή του k; Είναι εκείνη που ελαχιστοποιεί την παραπάνω
ποσότητα για όλα τα k στο διάστημα [i::j ¡ 1].
m2;4 = min
(
Συνδυάζοντας τα παραπάνω βρίσκουμε ότι το ελάχιστο κόστος παρενθετοποίησης της ακολουθίας
Mi £ ¢ ¢ ¢ £ Mj ικανοποιεί τη σχέση
m1;4 = min
8
>
< m1;1 + m2;4 + 10 ¢ 20 ¢ 100
mi;j =
(
0
Αν i = j
mini∙k<j (mi;k + mk+1;j + ri¡1 rk rj ) Αν i < j
(1)
Υπολογισμός Βέλτιστης Λύσης
Αντί να υπολογίσουμε τη λύση αναδρομικά (κάτι τέτοιο θα έπαιρνε εκθετικό χρόνο αφού θα λύναμε τα
ίδια υποπροβλήματα ξανά και ξανά) χρησιμοποιούμε τη προσέγγιση του δυναμικού προγραμματισμού
φυλάσοντας τις επιμέρους λύσεις σε ένα δισδιάτατο πίνακα. Συγκεκριμένα, υπολογίζουμε τις διάφορες
τιμές ξεκινώντας από κάτω προς τα πάνω.
Πρώτα υπολογίζουμε τα mi;i για κάθε i, έπειτα τα mi;i+1 για κάθε i, έπειτα τα mi;i+2 , κοκ. Με
αυτό τον τρόπο, οι όροι mi;k και mk+1;j στην (1) θα έχουν ήδη υπολογιστεί πριν το mi;j . Αυτό γιατί
το j ¡ i θα είναι μεγαλύτερο και από το k ¡i και από το j ¡(k +1). Ο αλγόριθμος φαίνεται παρακάτω:
m4;4 = 0
m2;2 + m3;4 + 20 ¢ 50 ¢ 100 = 15000
m2;3 + m4;4 + 20 ¢ 1 ¢ 100 = 3000
= 23000
m1;2 + m3;4 + 10 ¢ 50 ¢ 100 = 65000
>
:
m1;3 + m4;4 + 10 ¢ 1 ¢ 100 = 2200
Αν θέλουμε εκτός από την ελάχιστη τιμή 2200 να υπολογίζουμε και τη σειρά των πολλαπλασιασμών,
αρκεί να φυλάμε, για κάθε θέση του πίνακα, και την τιμή k που πετυχαίνει το ελάχιστο.
Εκτός από τον παραπάνω αλγόριθμο, ο οποίος αποφεύγει εντελώς την αναδρομή, υπάρχει και ένας
αναδρομικός αλγόριθμος που λύνει το ίδιο πρόβλημα σε πολυωνυμικό χρόνο. Το κόλπο είναι φυσικά
ότι κάνει χρήση αποθηκευμένων τιμών, αλλιώς θα απαιτούσε εκθετικό χρόνο αφού θα έλυνε συνεχώς
τα ίδια υποπροβλήματα.
Ο αλγόριθμος αυτός χρησιμοποιεί μία στρατηγική από πάνω προς τα κάτω διατηρώντας τις τιμές
λυμένων υποπροβλημάτων σε κάποιο πίνακα. Κάθε θέση του πίνακα αρχικά περιέχει μία ειδική τιμή
(όπως nil) για να φαίνεται ότι δεν έχει υπολογιστεί ακόμα η σωστή τιμή. Όταν ένα υποπρόβλημα
συναντηθεί για πρώτη φορά, υπολογίζεται η λύση του και αποθηκεύεται στον πίνακα. Από εκεί και
έπειτα το υποπρόβλημα αυτό δεν ξαναλύνεται αλλά αναζητείται η λύση του στον πίνακα.
Διδάσκων: Τάσος Δημητρίου
7
Ένας τέτοιος αλγόριθμος για την περίπτωση των πινάκων φαίνεται παρακάτω. Υποθέτουμε αρχικά
ότι όλες οι θέσεις mi;j του πίνακα περιέχουν την τιμή nil. Η πρώτη κλήση του αλγόριθμου είναι
φυσικά η RecMatrixProduct(1; n).
RecMatrixProduct(i; j)
= nil then return mi;j
if mi;j 6
if i = j
then mi;j = 0
else mi;j = mini∙k<j fRecMatrixProduct(i; k) + RecMatrixProduct(k + 1; j) +ri¡1 rk rj g
return mi;j
Γενικά, το πλεονέκτημα αυτής της μεθόδου είναι ότι λύνει μόνο τα υποπροβλήματα που είναι
απαραίτητα, όπως συναντώνται από την εφαρμογή της αναδρομική σχέσης, και όχι όλα όπως κάνει ο
πρώτος αλγόριθμος. Αν όμως χρειάζεται να λυθούν όλα τα υποπροβλήματα τουλάχιστον μία φορά, ο
πρώτος αλγόριθμος είναι πιο γρήγορος αφού δεν κάνει χρήση αναδρομής.
Εύρεση Συντομότερης Διαδρομής
Θεωρείστε το παρακάτω πρόβλημα:
Ένας καγάκιερ θέλει να κατέβει ένα ποτάμι με σκοπό να φτάσει από μια πόλη A σε μια πόλη
B. Το ποτάμι όμως είναι αρκετά \ιδιόρρυθμο" με την έννοια ότι υπάρχουν σημεία κόμβοι
στα οποία το ποτάμι διακλαδίζεται σε διαφορετικούς παραποτάμους. Κάθε τέτοια δυάδα
κομβικών σημείων i; j ορίζει μια διαδρομή, η οποία λόγω της διαφορετικής ορμητικότητας
των νερών παίρνει χρόνο tij για να διανυθεί. Αν είναι γωστός ο πίνακας χρόνου των
διαδρομών μπορείτε να βοηθήσετε τον καγιάκερ να βρει εκείνη την ακολουθία κομβικών
σημείων για να φτάσει από το A στο B στον ελάχιστο δυνατό συνολικό χρόνο;
1
8
5
2
1
3
3
4
5
4
10
2
5
2
6
2
8
Δυναμικός Προγραμματισμός
3 ο χρόνος του θα είναι 8 μονάδες (λεπτά, ώρες, μέρες, κλπ.) ενώ αν πάει στον 4 θα είναι μόνο 3
μονάδες. Από τον 4 μπορεί να συνεχίσει είτε στον 3 είτε στον 7. Στην πρώτη περίπτωση ο συνολικός
χρόνος θα είναι 3 + 2 = 5 μονάδες, ενώ στη δεύτερη θα είναι 3 + 5 = 8 μονάδες. Ποια λοιπόν είναι
η καλύτερη ακολουθία διαδρομών; Την απάντηση θα τη βρούμε με Δυναμικό Προγραμματισμό.
Για την ανάλυση θα θεωρήσουμε ότι η είσοδος δίνεται με τη μορφή ενός n £ n πίνακα t που
περιγράφει το χρόνο κάθε διαδρομής. Η τιμή t[i; j] του πίνακα θα δίνει ακριβώς το χρόνο της
διαδρομής και θα είναι ίση με 1 αν η διαδρομή αυτή δεν υφίσταται. Ας προσπαθήσουμε λοιπόν
να ακολουθήσουμε τα βήματα ανάλυσης που είδαμε στο παράδειγμα του πολλαπλασιασμού πινάκων.
Χαρακτηρισμός Βέλτιστης Λύσης
Ας δούμε πρώτα αν η βέλτιστη λύση παρουσιάζει optimal υποδομή. Θα χρησιμοποιήσουμε το συμβολισμό Ri;j για να υποδηλώσουμε την ακολουθία των διαδρομών που χρησιμοποιεί ο καγιάκερ για να
μεταβεί από το σημείο i στο σημείο j.
Έτσι το αρχικό μας πρόβλημα είναι απλά το R1;n . Είναι προφανές τώρα ότι ο καγιάκερ, στην
πορεία του από τον κόμβο 1 στον κόμβο n, θα πρέπει να περάσει από κάποιο ενδιάμεσο σημείο k,
για κάποιο 1 < k < n. Ο συνολικός χρόνος λοιπόν θα είναι ίσος με το άθροισμα του χρόνου για να
πάει από τον κόμβο 1 στον κόμβο k συν το χρόνο για να πάει από τον k στο n. Ας υποθέσουμε ότι ο
χρόνος του καγιάκερ είναι ο καλύτερος δυνατός.
Η σημαντική παρατήρηση τώρα είναι ότι κάθε μια από τις επιμέρους διαδρομές R1;k και Rk;n
πρέπει επίσης να είναι βέλτιστη. Ο λόγος είναι απλός: αν, για παράδειγμα, υπήρχε μία καλύτερη
ακολουθία για να πάει ο καγιάκερ από το 1 στο k θα μπορούσε να την είχε ακολουθήσει και να
πετύχαινε έτσι ακόμα καλύτερο χρόνο. Αυτό όμως δε μπορεί να συμβαίνει γιατί υποθέσαμε ότι η αρχική
ακολουθία είναι η καλύτερη δυνατή. Άρα η διαδρομή R1;k θα πρέπει να είναι βέλτιστη. Ανάλογα
ισχύουν και για τη διαδρομή Rk;n . Συμπεραίνουμε λοιπόν ότι η βέλτιστη λύση σε ένα στιγμιότυπο του
προβλήματος περιέχει βέλτιστες λύσεις σε υποπροβλήματα.
Αν συνεχίσουμε την ανάλυση θα δούμε ότι και κάθε μία από τις R1;k και Rk;n πρέπει επίσης
να διασπαστεί σε ενδιάμεσες διαδρομές. Με το ίδιο σκεπτικό κάθε μια από τις νέες υποδιαδρομές
πρέπει επίσης να είναι βέλτιστη. Φαίνεται λοιπόν ότι ο τύπος των υποπροβλημάτων είναι της μορφής
Ri;j για κάθε 1 ∙ i; j ∙ n. Πως συγκρίνεται αυτός με τον αριθμό των λύσεων; Ο αριθμός των
υποπροβλημάτων είναι φυσικά O(n2 ). Ο αριθμός όμως των δυνατών λύσεων είναι εκθετικά μεγάλος.
Κάθε λύση δεν είναι παρά μία ακολουθία της μορφής
5
7
7
8
1; u1 ; u2 ; : : : ; uk ; n
όπου τα ui είναι οποιοιδήποτε k από τους κόμβους 2 έως n ¡ 1, χωρίς επαναλήψεις όμως. Ο αριθμός
τους είναι
n¡2
X
8
k=0
Σχήμα 2: Ένα ποτάμι και οι επιμέρους διαδρομές του...
Ένα στιγμιότυπο του προβλήματος απεικονίζεται στο Σχήμα 2. Ο κόμβος 1 αντιστοιχεί στο σημείο
A και ο κόμβος 8 στο σημείο B. Οι ακμές που συνδέουν τους κόμβους αναπαριστούν τις διαδρομές
και τα βέλη τη κατεύθυνση των νερών. Η τιμή δίπλα σε κάθε ακμή αντιστοιχεί στο χρόνο περάσματος
της αντίστοιχης διαδρομής από τον καγιάκερ. Αν δύο κόμβοι δε συνδέονται με ακμή τότε διαδρομή
απαιτεί άπειρο χρόνο για να διανυθεί. Σκοπός του καγάκιερ είναι να πάει από τον κόμβο 1 στον κόμβο
8. Για παράδειγμα, ξεκινώντας από τον κόμβο 1 μπορεί να πάει είτε στον 3 είτε στον 4. Αν πάει στον
n=2
(n¡2
;
k )k! À (n=2)
κάτι που αποκλείει την απαρίθμησή τους. Εκείνο που θα κάνουμε λοιπόν είναι να λύσουμε όλα τα
υποπροβλήματα και να αποθηκεύσουμε τις λύσεις τους. Κάθε φορά που θα τα συναντά ο αλγόριθμος,
θα μπορεί να τα ανακαλεί με μικρό κόστος, ώστε η πολυπλοκότητα του να είναι πολυωνυμική.
Αναδρομικός Ορισμός Λύσης
Έχοντας ορίσει τα υποπροβλήματα, ο ορισμός της βέλτιστης λύσης γίνεται εύκολη υπόθεση. Θεωρείστε
την καλύτερη ακολουθία διαδρομών για να μεταβεί ο καγιάκερ από το σημείο i στο σημείο j. Έστω
Διδάσκων: Τάσος Δημητρίου
9
επίσης ότι η ακολουθία αυτή περιέχει το πολύ m διαδρομές (πλευρές του γραφήματος). Ας είναι
(m)
λοιπόν ri;j ο καλύτερος χρόνος που μπορεί να πετύχει ο καγιάκερ για να πάει από το i στο σημείο j
χρησιμοποιώντας το πολύ m ενδιάμεσες διαδρομές (πλευρές του γραφήματος). Γιατί όμως χρειάζεται
να ενσωματώσουμε και τον αριθμό των πλευρών m στον υπολογισμό του κόστους; Ο λόγος είναι
επειδή αν και μπορεί να έχουμε εντοπίσει την καλύτερη ακολουθία με m διαδρομές ωστόσο μπορεί να
υπάρχει μία ακόμα καλύτερη με m0 > m. Αν λοιπόν δε δοκιμάσουμε όλα τα m δε μπορούμε να είμαστε
σίγουροι ότι έχουμε εντοπίσει την καλύτερη. Πρέπει λοιπόν να καλύψουμε όλες τις περιπτώσεις, από
m = 1 έως m = n ¡ 1, αφού καμιά ακολουθία δε μπορεί να έχει μήκος μεγαλύτερο του n ¡ 1. Έτσι
(m)
για να ορίσουμε το ri;j χρειάζεται να εξετάσουμε όχι μόνο τις τιμές των i; j αλλά και την τιμή του
m.
1. m = 0.
Αν m = 0 τότε υπάρχει μία ακολουθία διαδρομών μηδενικού μήκους από το i στο j μόνο αν
i = j, δηλαδή ο καγιάκερ δε χρειάζεται να μεταβεί πουθενά. Αν i 6
= j τότε φυσικά κάτι τέτοιο
είναι αδύνατο, επομένως ο χρόνος θα θεωρήσουμε ότι είναι άπειρος. Συνοψίζοντας θα έχουμε:
(0)
ri;j =
2. m 6
= 0.
(
0;
1;
αν i = j
αν i =
6j
10
Δυναμικός Προγραμματισμός
(m)
όπου για κάθε m = 1; : : : ; n¡ 1 ο πίνακας r (m) θα περιέχει τις ποσότητες ri;j . Είναι προφανές επίσης
(1)
ri;j
ότι αφού
= ti;j θα έχουμε
= t.
Ο αλγόριθμος βασίζεται στην παρακάτω ρουτίνα η οποία δέχεται τους πίνακες r(m¡1) και t και
παράγει σαν έξοδο τον r (m) . Παράγει δηλαδή τις επόμενες καλύτερες διαδρομές μήκους m.
r (1)
NextBest(r; t)
r0 = new Matrix[n £ n]
for i = 1 to n do
for j = 1 to n do
0 = min
ri;j
1∙k<n fri;k + tk;j g
return r 0
Η ρουτίνα υπολογίζει τον πίνακα r0 , τον οποίο επιστρέφει στο τέλος. Αυτό το κάνει χρησιμοποιώντας
τον r σαν τον r (m¡1) και την εξίσωση (2) για τις τιμές του r (m) . Ο συνολικός χρόνος υπολογισμού
είναι O(n3 ) γιατί ο υπολογισμός του min παίρνει χρόνο O(n).
Ο χρόνος της καλύτερης διαδρομής μπορεί τώρα να υπολογιστεί με διαδοχικές εφαρμογές της
NextBest όπως φαίνεται παρακάτω:
r(2)
r(3)
(m)
Για τον υπολογισμό του ri;j όταν m ¸ 1, θα κάνουμε χρήση της ιδιότητας της βέλτιστης
υποδομής. Επειδή μάλιστα θέλουμε ο αναδρομικός ορισμός να είναι και συνάρτηση του m θα
(m)
προσπαθήσουμε να εκφράσουμε το ri;j συναρτήσει διαδρομών μήκους το πολύ m ¡ 1. Έτσι η
καλύτερη ακολουθία m διαδρομών μεταξύ i και j θα πρέπει να διασπάται σε δύο μέρη: το πρώτο
για να πάει από το σημείο i σε ένα σημείο k χρησιμοποιώντας το πολύ m ¡ 1 βήματα, και το
δεύτερο για να πάει από το k στο j σε ένα βήμα. Το k τώρα μπορεί να είναι οποιοσδήποτε από
τους άλλους κόμβους.
Άρα ο χρόνος μετάβασης από το i στο j χρησιμοποιώντας το πολύ m ενδιάμεσες διαδρομές θα
είναι ίσος με το χρόνο μετάβασης από το i στο k χρησιμοποιώντας το πολύ m ¡ 1 διαδρομές
συν το χρόνο tk;j της διαδρομής από το k στο j. Και ποια είναι η καλύτερη τιμή του k; Είναι
(m)
αυτή που ελαχιστοποιεί το παραπάνω άθροισμα. Το ri;j θα εκφράζεται λοιπόν από τη σχέση:
(m)
ri;j
=
(m¡1)
min fr
1∙k∙n i;k
+ tk;j g:
(2)
Προσέξτε ότι εδώ επιτρέπουμε στο k να λάβει οποιαδήποτε τιμή. Συγκεκριμένα, αν k = j
παίρνουμε το άθροισμα
(m¡1)
(m¡1)
ri;j
+ tj;j = ri;j
;
= NextBest(r (1) ; t)
= NextBest(r (2) ; t)
..
.
r(n¡1) = NextBest(r (n¡2) ; t)
ή υπό μορφή αλγορίθμου
BestSequence(t)
r = new Matrix[n £ n]
r=t
for m = 2 to n ¡ 1 do
r = NextBest(r; t)
return r
Ο τελευταίος αυτός αλγόριθμος παίρνει χρόνο O(n4 ). Ο πίνακας που επιστρέφει περιέχει τις
καλύτερες ακολουθίες, μήκους το πολύ m ¡ 1, από όλους τους κόμβους προς όλους τους κόμβους
και όχι μόνο από τον κόμβο 1 στον κόμβο n. Αυτό συμβαίνει συχνά σε αλγόριθμους εύρεσης
συντομότερων μονοπατιών. Σαν παράγωγο υπολογίζονται μονοπάτια, όχι μόνο μεταξύ των κόμβων
που μας ενδιαφέρουν αλλά και μεταξύ άλλων κόμβων.
επειδή tj;j = 0. Αυτό σημαίνει ότι μέσα στις ποσότητες που συγκρίνονται (από τη συνάρτηση
(m¡1)
. Και αυτό είναι σωστό. Γιατί ήδη ο μικρότερος χρόνος
min) στην (2) υπάρχει και η ri;j
μπορεί να έχει επιτευχθεί από μία ακολουθία με μικρότερο m οπότε δε θα θέλαμε να χάσουμε
αυτή την πληροφορία.
Υπολογισμός Βέλτιστης Λύσης
:-)
Θα υπολογίσουμε τους καλύτερους χρόνους χρησιμοποιώντας μία προσέγγιση από κάτω προς τα πάνω.
Χρησιμοποιώντας τον πίνακα εισόδου t θα υπολογίσουμε μία ακολουθία από πίνακες r (1) ; r(2) ; : : : ; r(n¡1) ,
Ïé óçìåéþóåéò áõôÝò áðïôåëïýí ôìÞìá âéâëßïõ. Äåí
åðéôñÝðåôáé ç ÷ñÞóç ôïõò ãéá ðáñáãùãÞ äéäáêôéêïý
Þ Üëëïõ õëéêïý ÷ùñßò ôçí Üäåéá ôïõ óõããñáöÝá.