ΑΝΑ ΡΟΜΗ- ΑΣΚΗΣΕΙΣ Μια µέθοδος είναι αναδροµική όταν καλεί τον εαυτό της και έχει µια συνθήκη τερµατισµού π.χ. το παραγοντικό ενός αριθµού Ν, µπορεί να καλεί το παραγοντικό του αριθµού Ν-1 το παραγοντικό του αριθµού Ν-1, µπορεί να καλεί το παραγοντικό του αριθµού Ν-2 κ.ο.κ. και η συνθήκη τερµατισµού του είναι: όταν το Ν<=0 το παραγοντικό ισούται µε 1 1. Παραγοντικό 1 Ν!=1*2*3* *(N-1) * N => N! = (Ν-1)! * N έτσι 55! = 54! * 55 4! = 1*2*3*4 = 3! * 4 4! = 6 * 4 = 24 3! = 1*2*3 = 2! * 3 3! = 2 * 3 = 6 2! = 1*2 = 1! *2 2! = 1 * 2 = 2 1! = 1=1!* 1 1! = 1 0! = 1 0! = 1 public static int factorial (int num) { if (num..) return 1; else return factorial( ); public static void main (String args[]) { System.out.println("Calculating Factorial"); int n; int result; System.out.print("\nPlease give number : "); n = UserInput.getInteger(); result = factorial(n) ; System.out.println("Factorial of "+n+" is "+result+"\n"); 2. Ακολουθία Fibonacci Kάθε αριθµός ισούται µε το άθροισµα των 2 προηγούµενων.(κουνέλια /µήνα /ζεύγος 1ζεύγος) Συνθήκη Τερµατισµού: Οι δύο πρώτοι είναι ίσοι 1. Fibonacci(N)= Fibonacci(N-1) + Fibonacci(N-2) f(1) f( 2) f(3) f(4) f(5) f(6) f(7) f(8) 1 1 2 3 5 8 13 21 1+1=2 1+2=3 2+3=5 3+5=8 5+8=13 8+13=21 1 Στην Java ένας int µπορεί να πάρει τιµές από -2.147.483.648 µέχρι 2.147.483.647 (= 2 31-1). To factorial(12) ισούται µε 479.001.600 άρα δεν µπορεί µε ιnt να υπολογιστεί factorial >12. Eνας long µπορεί να πάρει τιµές µέχρι 2 63-1.έτσι υπολογίζεται το factorial(13)=6.227.020.800. Μπορείτε να χρησιµοποιήστε και java.math.biginteger Οι τιµές 12! and 20! είναι τα µεγαλύτερα factorials που µπορούν να αποθηκευτούν, αντίστοιχα, σε 32-bit και 64-bit integers (http://en.wikipedia.org/wiki/factorial /6.Computation) Η τιµή του 170! είναι ο µεγαλύτερος factorial που αναπαρίσταται µε floating-point approximation. Υπολογισµός του Ν! στο http://math.about.com/library/blcalcfactorial.htm [1] ΕΑΡ 2015
3. Υπολογισµός Παλίνδροµου αριθµού Παλίνδροµος είναι ο αριθµός 2 που, είτε διαβάζεται από αριστερά προς δεξιά, είτε από δεξιά προς τα αριστερά είναι ίδιος, δηλ. τα στοιχεία του είναι «συµµετρικά» ως προς το κέντρο. Το ίδιο και ισχύει για ένα string. π.χ. οι αριθµοί 12321, 1221, 1234321, 2222, 151, 11, 33 κτλ. είναι παλίνδροµοι ενώ οι 15321 και 567 δεν είναι παλίνδροµοι. [Επίσης το string abba είναι παλίνδροµο ενώ το abac δεν είναι. Για να ελένξω αν οι συµβολοσειρές π.χ. abac abba είναι παλίνδροµες ή όχι, µπορώ π.χ. να ελέγξω αν ο 1 ος χαρακτήρας (το a)και ο τελευταίος χαρακτήρας (το c στην 1 η και το a στην 2 η ) είναι ίδιοι και αν αν δεν είναι ίδιοι (abac) να αποφανθώ ότι η σειρά δεν είναι παλίνδροµη αν είναι ίδιοι (abba) θα ελέγξω µε τον ίδιο τρόπο το υπολειπόµενο string δηλ. το bb Συνθήκη τερµατισµού : αν έχει µόνο ένα ή κανένα γράµµα τότε είναι παλίνδροµη.] Παρόµοια ισχύει και για ένα αριθµό που θα µπορούσε ή να µετατραπεί σε string ή να γενικότερα να χωριστεί στα ψηφία του, διαιρούµενος µε το 10 ή µε δυνάµεις του 10. Αν επιλέξουµε την λύση διαίρεσης µε το 10 θα χρησιµοποιηθεί το div και το mod (διαίρεση και υπόλοιπο ακέραιης διαίρεσης - στη JAVA είναι τα / και %). Για να ελέγξω αν ο αριθµός π.χ. Ν = 15321 είναι παλίνδροµος ή όχι, µπορώ να δηµιουργήσω τον ανάποδό του (δηλ. το 12351) και να τους συγκρίνω. Έτσι θα εντοπίσω το τελευταίο του ψηφίο (1), από το υπόλοιπο της διαίρεσής του µε το 10, και θα κάνω το ίδιο αναδροµικά (δηλ. θα εντοπίσω το τελευταίο ψηφίο) αλλά µε νέο αριθµό, (το 1532), που είναι το πηλίκο του αριθµού µε το 10 και κάθε φορά που βρίσκω το τελευταίο ψηφίο θα δηµιουργώ ένα νέο αριθµό (που τελικά θα είναι ο διαβασµένος ανάποδα αριθµός) και αυτόν θα συγκρίνουµε. Συνθήκη τερµατισµού ο αριθµός/πηλίκο να ισούται µε 0. Ν Πηλίκο Υπόλοιπο mirror_num 15321 / 10 = 1532 15321 % 10 =1 0 *10 + 1 = 1 1532 / 10 = 153 1532 % 10 =2 1 *10 + 2 = 12 153 / 10 = 15 153 % 10 =3 12*10 + 3 = 123 15 / 10 = 1 15 % 10 =5 123*10 + 5 = 1235 1 / 10 = 0 1 % 10 =1 1235*10+ 1= 12351. if ( Ν == mirror(ν) ) / / OK είναι ίδιοι αριθµοί Και εποµένως ο Ν είναι παλίνδροµος mirror_num = mirror_num * 10 + N % 10 (αρχικό mirror_num = 0) Παραλλαγή : Eλέγξτε µία συµβολοσειρά 3 (string) εάν είναι παλίνδροµη ή όχι. 2 Στην εισαγωγή αριθµού θα εµφανίζεται µήνυµα λάθους στις περιπτώσεις που δεν δίνεται από τον χρήστη θετικός και έως πενταψήφιος ακέραιος και σε περίπτωση σφάλµατος ο χρήστης θα πρέπει να δώσει εκ νέου κάποιον αριθµό. Το πρόγραµµα σας θα πρέπει να δέχεται 10 εισαγωγές αριθµών από κάθε χρήστη. 3 Σε ένα String s µπορούν να χρησιµοποιηθούν π.χ.οι µέθοδοι s.charat(0) : o χαρακτήρας στην θέση 0 s.length : το µήκος της συµβολοσειράς [2] ΕΑΡ 2015
4. Πρώτοι αριθµοί 4 : 2, 3, 5, 7, 11, 13, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, Ενας φυσικός αριθµός µεγαλύτερος από την µονάδα, που διαιρείται µόνο µε τον εαυτό του και το 1 ονοµάζεται πρώτος αριθµός αλλιώς λέγεται σύνθετος αριθµός 5. (Το 7 είναι πρώτος αριθµός, γιατί οι µόνοι διαιρέτες του είναι το 1 και το 7, ενώ το 8 δεν είναι πρώτος αλλά σύνθετος γιατί διαιρείται εκτός από το 1 και το 8 και µε το 2, δηλ. 8%2=0). Θα αναφέρουµε ενδεικτικά 2 τρόπους επίλυσης: a. Απλός τρόπος µη αναδροµικός προκύπτει από τον ορισµό του πρώτου αριθµού Αν υπάρχει έστω και ένα i ώστε Ν % i να ισούται µε 0 (µε i=2,3..ν-1) τότε Ν δεν είναι πρώτος. b. Αναδροµικός τρόπος µε τον αλγόριθµο του WILSON 6 : Αν το (1+factorial (N-1)) % N ισούται µε 0 τότε το Ν είναι πρώτος αριθµός. Παραλλαγή : Εµφανίστε όλους τους πρώτους αριθµούς 7 από το 1 µέχρι το 10.000. http://primes.utm.edu/lists/small/10000.txt Αναδροµικά µπορούν να επιλυθούν διάφορα προβλήµατα π.χ. Υπολογισµός της δύναµης ενός αριθµού Εύρεση ελάχιστου στοιχείου ακολουθίας Υπολογισµός ΜΚ / αλγόριθµος Ευκλείδη ΜΚ (x,y) = MΚ (y,x%y) x,y 0 Εύρεση µεγέθους ενός Φακέλου (directory) Καταµέτρηση πλήθους των κόµβων σε µια συνδεδεµένη λίστα κτλ. Οι αναδροµικοί αλγόριθµοι βασίζονται στην ιδέα του «διαίρει και βασίλευε»: Ενα πρόβληµα µεγέθους Ν διασπάται πρόβληµα µεγέθους k κ.ο.κ σε υποπροβλήµατα πρόβληµα µεγέθους Ν-k & επιλύουµε αναδροµικά τα υποπροβλήµατα. Χαρακτηριστικό παράδειγµα οι Πύργοι του Ανόϊ 5. Πύργοι του Ανόϊ http://www.mazeworks.com/hanoi/ http://www.wolframalpha.com/input/?i=tower+of+hanoi Έχουµε µία κατασκευή µε τρείς στύλους και N δίσκους. Στον πρώτο είναι περασµένοι N δίσκοι. Πρέπει να µεταφέρουµε τους δίσκους από τον αρχικό στύλο όπου βρίσκονται, σε ένα άλλο χρησιµοποιώντας τον τρίτο στύλο σαν βοηθητικό µε τους ακόλουθους περιορισµούς: Μόνο ένας δίσκος µπορεί να µετακινηθεί κάθε φορά. εν είναι δυνατόν να τοποθετηθεί µεγαλύτερος δίσκος πάνω από ένα µικρότερο. s.substring(1,3) : η συµβολοσειρά από την θέση 1 έως την 3 καθώς και άλλες µέθοδοι, κοίταξε στο https://docs.oracle.com/javase/6/docs/api/java/lang/string.html 4 Ο αριθµός 2 είναι ο µόνος άρτιος (ζυγός) πρώτος αριθµός. Όλοι οι άλλοι πρώτοι είναι περιττοί (µονοί). 5 Το Θεµελιώδες Θεώρηµα της Αριθµητικής βεβαιώνει πως κάθε φυσικός µεγαλύτερος της µονάδας είτε είναι πρώτος είτε εκφράζεται µε µοναδικό τρόπο ως γινόµενο πρώτων παραγόντων π.χ.το 30=2*3*5. 6 Η µέθοδος αυτή δεν εφαρµόζεται για µεγάλο Ν, αφού είναι δύσκολο να υπολογιστεί το παραγοντικό. 7 Οι πρώτοι αριθµοί είναι χρήσιµοι στην κρυπτογραφία. Πόσοι είναι; Μέχρι το 1000 υπάρχουν 168 πρώτοι αριθµοί, µέχρι το 10.000 υπάρχουν 1.229 κτλ. Ένας από τους πιο απλούς αλλά και αργούς τρόπους για (µαζική) εύρεση πολλών πρώτων είναι το λεγόµενο κόσκινο του Ερατοσθένη: αρχίζουµε και αποκλείουµε πρώτα τα πολλαπλάσια του 2 µετά τα πολλαπλάσια του επόµενου µη διαγραµµένου αριθµού κ.ο.κ. έως το Ν. Μια πιο αποδοτική σύγχρονη εκδοχή είναι το κόσκινο του Atkin. Μπορείτε να παράγετε πρώτους - όχι όλους, αρχίζοντας µε το 2, από την σχέση Ν=P+1, όπου P είναι το γινόµενο όλων των πρώτων που έχουν παραχθεί µέχρι τότε (Ν=2+1=3, Ν=2*3+1=7, Ν=2*3*7+1=43 κλπ.) [3] ΕΑΡ 2015
Θα µετακινήσουµε όλους τους δίσκους από τον 1 ο στύλο στον 2 ο στύλο. Έστω ότι ξέρουµε να µετακινούµε τους πρώτους N-1 δίσκους σε άλλο στύλο (π.χ. στον 3 ο στύλο). Τότε µας αποµένει στον 1 ο στύλο ο δίσκος Ν, που θα πρέπει και αυτός να µεταφερθεί στον 2 ο στύλο. Τότε ο δίσκος Ν θα µεταφερθεί στον 2 ο στύλο και το πρόβληµα αυτόµατα λύνεται γιατί ξέρουµε πώς να µετακινούµε N-1 δίσκους σε άλλο στύλο και έτσι θα µεταφέρουµε τους Ν-1 δίσκους που βρίσκονται στον 3 ο στύλο, στον 2 ο στύλο, πάνω από τον Ν ίσκο. Γίνεται έτσι κατανοητό ότι σε κάθε µεταφορά (transfer) Ν δίσκων, υπάρχει ένας στύλος αφετηρία (source), ένας στύλος προορισµός (destination), και ένας βοηθητικός/αποθηκευτικός (storage). Η µέθοδος µεταφορά µπορεί να περιγραφεί ως εξής: transfer(int Ν, char source, char destination, char storage) Στο παρακάτω παράδειγµα µεταφοράς 3 δίσκων θα ονοµάσουµε τους στύλους Α,Β,C. A Β C Εστω ότι θέλω να πάω 3 δίσκους από τον Α στον B στύλο µε βοηθητικό τον C δηλ. θα δώσω µια εντολή transfer(3, 'A', 'B', 'C'); * Μεταφέρω τους 2 δίσκους από τον Α στο C ** Bάζω τον τελευταίο δίσκο στο Β (print..) ** Μεταφέρω τους 2 δίσκους από τον C στο B Οι δυο στoν C O 3 os στον B Λύνω ένα πρόβληµα µικρότερο (µε 2 δίσκους) [4] ΕΑΡ 2015
public static void transfer (int Ν, char source, char destination, char storage) { if (Ν == 0) return; //Transfer Ν-1 discs the temporary storage // transfer ( ); //Transfer the last disc to the destination System.out.println( "Moving disc "+ discs+" from "+source+" to "+destination);** //Transfer Ν-1 discs, from the temporary storage to the destination // transfer ( ); [5] ΕΑΡ 2015