Mηνιαία Πρόκληση: Ιανουάριος 2021
-
- Δημοσιεύσεις: 6
- Εγγραφή: Τρί Δεκ 22, 2020 3:46 pm
Mηνιαία Πρόκληση: Ιανουάριος 2021
Καλή Χρονιά σε ολούς, συνεχίζουμε με τις μηνιαίες προκλήσεις, και μπαίνουμε στον Iανουάριο.
Κάθε αρχή του μήνα θα ανεβαίνει στο pdpforum ένα πρόβλημα προς συζήτηση.
Στα σχόλια μπορεί να ξεκινήσει συζήτηση εάν έχετε κάποια απορία για το πρόβλημα, ή κάποια παρατήρηση, οσοδήποτε απλή, που πιστεύετε μπορεί να βοηθήσει αλλά δεν ξέρετε πώς.
Οι απαντήσεις και οι παρατηρήσεις ας μπαίνουν σε spoiler tags βέβαια!
Περίπου στο τέλος του μήνα θα δίνεται ένα link για σύσκεψη στην οποία θα συζητάμε όλοι μαζί το πρόβλημα, τις λύσεις μας, πιθανές βελτιώσεις, κλπ.
Σημείωση: Ένας από τους συμμετέχοντες της σύσκεψης θα επιλέγεται ώστε να βοηθήσει τον Βαγγέλη με την επόμενη μηνιαία πρόκληση, αυτή του Φεβρουαριού εν προκειμένω.
Οι αρμοδιότητές του θα είναι να λύσει το επόμενο πρόβλημα εντός του μήνα (εννοείται με συνεννόηση/βοήθεια από τον Βαγγέλη) ώστε να είναι σε θέση να λύνει απορίες στην επόμενη σύσκεψη και στο forum.
(Και πάλι, εννοείται θα είναι κι o Βαγγέλης στη σύσκεψη, οπότε δεν αγχωνόμαστε "Τι θα γίνει αν δε μπορώ να απαντήσω σε κάποια ερώτηση;").
Από τη σύσκεψη Δεκεμβρίου έχει επιλεγεί ήδη ο Ανδρέας (εγώ) ως βοηθός Ιανουαρίου ο οποίος εφτιαξε και ολόκληρο βίντεο εξηγώντας το προβλημα και την λύση του (θα δοθεί μετά την κλήση).
Σε αυτό το πρόβλημα έχουμε έναν δρόμο οπού έχει 2 πλέυρες, και κάθε πλευρά είναι χωρισμένη σε Ν κομμάτια (sections).
Θέλουμε σε κάθε πλευρά (ανεξάρτητα), κάθε ένα από τα Ν κομμάτια είτε να το αφήσουμε κένο είτε να χτίσουμε ένα κτήριο. Πρέπει όμως να ισχύει ότι σε κάθε πλευρά δε μπορούν να υπάρχουν 2 συνεχόμενα κτήρια χτισμένα δίπλα δίπλα.
Στόχος μας είναι να βρούμε τους συνολικούς πλήθος τρόπων να χτίσουμε κτήρια καθώς και να ισχύουν οι παραπάνω περιορισμοί.
Θα ισχύει Ν<=2^60. Επειδή το αποτέλεσμα μπορεί να είναι πολύ μεγάλο, θέλουμε να τυπώσουμε το υπόλοιπο της ακέραιας διαίρεσής του (modulo) με το (10^9+7).
Παραδείγματα
Αν Ν=1 τότε υπάρχουν 4 τρόποι.
Ας πούμε Κ το κενό κομμάτι και B αυτό που έχει χτισμένο κτήριο.
Τοτέ μπορούμε να κάνουμε τα παρακάτω 4:
Πρώτη πλευρά: Δέυτερη πλευρά:
K K
B B
B K
K B
Αν Ν=2 τότε υπάρχουν 9 τρόποι:
Πρώτη πλευρά: Δέυτερη πλευρά:
KΚ KΚ
ΚΚ ΒΚ
ΚΚ ΚΒ
KΒ KΚ
ΚΒ ΒΚ
ΚΒ ΚΒ
ΒΚ KΚ
ΒΚ ΒΚ
ΒΚ ΚΒ
Όπως βλέπετε δεν μπορούμε να βάλουμε ΒΒ.
Bonus πληροφορία: Το παραπάνω πρόβλημα μπορεί να λυθεί σε Ο(log N) χρόνο. Δοκιμάστε αρχικά να πετύχετε χρόνο Ο(Ν), και κατόπιν οτιδήποτε καλύτερο (έστω κι αν δεν είναι Ο(log N)).
Στις 20 του μηνός θα δώσουμε ένα hint, θυμίστε το μας αν το ξεχάσουμε.
Καλή επιτυχία!
Κάθε αρχή του μήνα θα ανεβαίνει στο pdpforum ένα πρόβλημα προς συζήτηση.
Στα σχόλια μπορεί να ξεκινήσει συζήτηση εάν έχετε κάποια απορία για το πρόβλημα, ή κάποια παρατήρηση, οσοδήποτε απλή, που πιστεύετε μπορεί να βοηθήσει αλλά δεν ξέρετε πώς.
Οι απαντήσεις και οι παρατηρήσεις ας μπαίνουν σε spoiler tags βέβαια!
Περίπου στο τέλος του μήνα θα δίνεται ένα link για σύσκεψη στην οποία θα συζητάμε όλοι μαζί το πρόβλημα, τις λύσεις μας, πιθανές βελτιώσεις, κλπ.
Σημείωση: Ένας από τους συμμετέχοντες της σύσκεψης θα επιλέγεται ώστε να βοηθήσει τον Βαγγέλη με την επόμενη μηνιαία πρόκληση, αυτή του Φεβρουαριού εν προκειμένω.
Οι αρμοδιότητές του θα είναι να λύσει το επόμενο πρόβλημα εντός του μήνα (εννοείται με συνεννόηση/βοήθεια από τον Βαγγέλη) ώστε να είναι σε θέση να λύνει απορίες στην επόμενη σύσκεψη και στο forum.
(Και πάλι, εννοείται θα είναι κι o Βαγγέλης στη σύσκεψη, οπότε δεν αγχωνόμαστε "Τι θα γίνει αν δε μπορώ να απαντήσω σε κάποια ερώτηση;").
Από τη σύσκεψη Δεκεμβρίου έχει επιλεγεί ήδη ο Ανδρέας (εγώ) ως βοηθός Ιανουαρίου ο οποίος εφτιαξε και ολόκληρο βίντεο εξηγώντας το προβλημα και την λύση του (θα δοθεί μετά την κλήση).
Σε αυτό το πρόβλημα έχουμε έναν δρόμο οπού έχει 2 πλέυρες, και κάθε πλευρά είναι χωρισμένη σε Ν κομμάτια (sections).
Θέλουμε σε κάθε πλευρά (ανεξάρτητα), κάθε ένα από τα Ν κομμάτια είτε να το αφήσουμε κένο είτε να χτίσουμε ένα κτήριο. Πρέπει όμως να ισχύει ότι σε κάθε πλευρά δε μπορούν να υπάρχουν 2 συνεχόμενα κτήρια χτισμένα δίπλα δίπλα.
Στόχος μας είναι να βρούμε τους συνολικούς πλήθος τρόπων να χτίσουμε κτήρια καθώς και να ισχύουν οι παραπάνω περιορισμοί.
Θα ισχύει Ν<=2^60. Επειδή το αποτέλεσμα μπορεί να είναι πολύ μεγάλο, θέλουμε να τυπώσουμε το υπόλοιπο της ακέραιας διαίρεσής του (modulo) με το (10^9+7).
Παραδείγματα
Αν Ν=1 τότε υπάρχουν 4 τρόποι.
Ας πούμε Κ το κενό κομμάτι και B αυτό που έχει χτισμένο κτήριο.
Τοτέ μπορούμε να κάνουμε τα παρακάτω 4:
Πρώτη πλευρά: Δέυτερη πλευρά:
K K
B B
B K
K B
Αν Ν=2 τότε υπάρχουν 9 τρόποι:
Πρώτη πλευρά: Δέυτερη πλευρά:
KΚ KΚ
ΚΚ ΒΚ
ΚΚ ΚΒ
KΒ KΚ
ΚΒ ΒΚ
ΚΒ ΚΒ
ΒΚ KΚ
ΒΚ ΒΚ
ΒΚ ΚΒ
Όπως βλέπετε δεν μπορούμε να βάλουμε ΒΒ.
Bonus πληροφορία: Το παραπάνω πρόβλημα μπορεί να λυθεί σε Ο(log N) χρόνο. Δοκιμάστε αρχικά να πετύχετε χρόνο Ο(Ν), και κατόπιν οτιδήποτε καλύτερο (έστω κι αν δεν είναι Ο(log N)).
Στις 20 του μηνός θα δώσουμε ένα hint, θυμίστε το μας αν το ξεχάσουμε.
Καλή επιτυχία!
-
- Δημοσιεύσεις: 6
- Εγγραφή: Τρί Δεκ 22, 2020 3:46 pm
Re: Mηνιαία Πρόκληση: Ιανουάριος 2021
Καλησπέρα μόλις τώρα ήρθε η courier και έφερε τα hint όχι σαν τις άλλες φορες που άργησε λόγω covid
1) Δείξτε ότι αν γνωρίζαμε τους τρόπους να βάλουμε κτήρια στη μία πλευρά του δρόμου, θα μπορούσαμε αυτόματα να υπολογίσουμε τη λύση στο πρόβλημά μας.
2) Ας επικεντρωθούμε μόνο στη μία πλευρά του δρόμου. Θέλουμε να υπολογίσουμε αναδρομικά τη λύση μας. Υπάρχουν δύο βασικές προσεγγίσεις (και οι 2 στηρίζονται στο να εξετάσουμε αν θα μπει ή δε θα μπει κτήριο στην τελευταία θέση.
Α) Πρέπει να υπολογίσουμε αναδρομικά τα
-Πλήθος_Τρόπων(Ν οικόπεδα, Χτίζω κτήριο στο τελευταίο οικόπεδο)
-Πλήθος_Τρόπων(Ν οικόπεδα, Δε χτίζω κτήριο στο τελευταίο οικόπεδο)
Β) Πρέπει να υπολογίσουμε αναδρομικά το
-Πλήθος_Τρόπων(Ν οικόπεδα)
Διαλέξτε όποιο απ' το (Α) ή (Β) σας φαίνεται πιο προσιτό, και προσπαθήστε να βρείτε μια αναδρομική σχέση για αυτό.
Για όποιον δεν ξέρει τι ακριβώς είναι οι αναδρομικές σχέσεις, θα θέλαμε, για το (Α) κάτι του τύπου:
Πλήθος_Τρόπων(Ν οικόπεδα, Χτίζω) = Πλήθος_Τρόπων(Ν-1 οικόπεδα, Δε χτίζω) + Πλήθος_Τρόπων(Ν-2 οικόπεδα, Χτίζω)
κι αντίστοιχα μια τέτοια σχέση για το Πλήθος_Τρόπων(Ν οικόπεδα, Δε χτίζω).
Τονίζω ότι η σχέση που έχω γράψει είναι λάθος, απλά περιμένουμε ότι κάπως έτσι μοιάζει η μορφή της σωστής, και πρέπει να βάλετε τη λογική σας για να καταλάβετε πώς ακριβώς θα μοιάζει.
Καλή επιτυχία σε όλους.
1) Δείξτε ότι αν γνωρίζαμε τους τρόπους να βάλουμε κτήρια στη μία πλευρά του δρόμου, θα μπορούσαμε αυτόματα να υπολογίσουμε τη λύση στο πρόβλημά μας.
2) Ας επικεντρωθούμε μόνο στη μία πλευρά του δρόμου. Θέλουμε να υπολογίσουμε αναδρομικά τη λύση μας. Υπάρχουν δύο βασικές προσεγγίσεις (και οι 2 στηρίζονται στο να εξετάσουμε αν θα μπει ή δε θα μπει κτήριο στην τελευταία θέση.
Α) Πρέπει να υπολογίσουμε αναδρομικά τα
-Πλήθος_Τρόπων(Ν οικόπεδα, Χτίζω κτήριο στο τελευταίο οικόπεδο)
-Πλήθος_Τρόπων(Ν οικόπεδα, Δε χτίζω κτήριο στο τελευταίο οικόπεδο)
Β) Πρέπει να υπολογίσουμε αναδρομικά το
-Πλήθος_Τρόπων(Ν οικόπεδα)
Διαλέξτε όποιο απ' το (Α) ή (Β) σας φαίνεται πιο προσιτό, και προσπαθήστε να βρείτε μια αναδρομική σχέση για αυτό.
Για όποιον δεν ξέρει τι ακριβώς είναι οι αναδρομικές σχέσεις, θα θέλαμε, για το (Α) κάτι του τύπου:
Πλήθος_Τρόπων(Ν οικόπεδα, Χτίζω) = Πλήθος_Τρόπων(Ν-1 οικόπεδα, Δε χτίζω) + Πλήθος_Τρόπων(Ν-2 οικόπεδα, Χτίζω)
κι αντίστοιχα μια τέτοια σχέση για το Πλήθος_Τρόπων(Ν οικόπεδα, Δε χτίζω).
Τονίζω ότι η σχέση που έχω γράψει είναι λάθος, απλά περιμένουμε ότι κάπως έτσι μοιάζει η μορφή της σωστής, και πρέπει να βάλετε τη λογική σας για να καταλάβετε πώς ακριβώς θα μοιάζει.
Καλή επιτυχία σε όλους.
-
- Δημοσιεύσεις: 33
- Εγγραφή: Σάβ Φεβ 08, 2020 5:39 pm
Re: Mηνιαία Πρόκληση: Ιανουάριος 2021
Υπάρχει κάποιο λάθος με την εκφώνηση ή δεν καταλαβαίνω κάτι; 2^60 είναι ο μεγαλύτερος αριθμός κομματιών ή ο μεγαλύτερος αριθμός του πλήθους τρόπων; Γιατί αν είναι ο αριθμός κομματιών, οι πιθανοί συνδυασμοί θα είναι μεγαλύτερος αριθμός από ότι χωράει σε οποιοδήποτε τύπο δεδομένων με πολύ μεγάλη διαφορά..
Re: Mηνιαία Πρόκληση: Ιανουάριος 2021
2^60 ειναι το μεγιστο οριου αριθμου κομματιών. Το πληθος διαφορετικών συνδιασμων ειναι οπως ειπες πολυ μεγαλυτερο αλλα δεν μας το ζητα οποτε δεν χρειαζεται να το αποθηκευσεις. Αντι αυτου πρεπει να επιστρεψεις το υπολοιπο της διαίρεσης του με καποιον πρωτο αριθμο πχ 10^9+7.
Αν δεν καταλαβες τι σημασια εχει το υπολοιπο της διαιρεσης, δες πχ εδω:
https://www.geeksforgeeks.org/modular-arithmetic/
Αν δεν καταλαβες τι σημασια εχει το υπολοιπο της διαιρεσης, δες πχ εδω:
https://www.geeksforgeeks.org/modular-arithmetic/
-
- Δημοσιεύσεις: 33
- Εγγραφή: Σάβ Φεβ 08, 2020 5:39 pm
Re: Mηνιαία Πρόκληση: Ιανουάριος 2021
πως θα μπορούσα να μην αποθηκέψω τον αριθμό;
Re: Mηνιαία Πρόκληση: Ιανουάριος 2021
Αποθηκευεις σε long long οταν εχεις υπολογισει για κ κομματια και κανεις modulo με 10^9+7.
Tον ακριβη αριθμο δεν τον χρειαζεσαι, μονο το υπόλοιπο.
Μετα υπολογιζεις για κ+1 και προσαυξανεις αναλογα τον long long σου ξανακανοντας modulo .
Με τον τροπο αυτο δεν προκειται να χρειαστεις περισσοτερο απο 64 bits (η τελικη απαντηση χωρα σε 32bits αλλα θελεις το long long για να μην κανεις overflow μεχρι να κανεις το modulo)
Tον ακριβη αριθμο δεν τον χρειαζεσαι, μονο το υπόλοιπο.
Μετα υπολογιζεις για κ+1 και προσαυξανεις αναλογα τον long long σου ξανακανοντας modulo .
Με τον τροπο αυτο δεν προκειται να χρειαστεις περισσοτερο απο 64 bits (η τελικη απαντηση χωρα σε 32bits αλλα θελεις το long long για να μην κανεις overflow μεχρι να κανεις το modulo)
-
- Δημοσιεύσεις: 33
- Εγγραφή: Σάβ Φεβ 08, 2020 5:39 pm
Re: Mηνιαία Πρόκληση: Ιανουάριος 2021
οκ ευχαριστώ!
-
- Δημοσιεύσεις: 6
- Εγγραφή: Τρί Δεκ 22, 2020 3:46 pm
Re: Mηνιαία Πρόκληση: Ιανουάριος 2021
Καλησπέρα σε όλους!
Η συνάντηση θα γίνει το επόμενο Σάββατο, 30 Ιανουαρίου, 15:00 ώρα Ελλάδος.
Το link για το zoom είναι: https://ucph-ku.zoom.us/j/67586825824?p ... sveG9qZz09
Meeting ID: 675 8682 5824
Passcode: 988982
Μην ξεχάσετε να κατεβάσετε την εφαρμογή του zoom για να έχετε πρόσβαση στον ασπροπίνακα, καθώς η online έκδοση δε δίνει τέτοια δυνατότητα.
Τα λέμε τότε!
Η συνάντηση θα γίνει το επόμενο Σάββατο, 30 Ιανουαρίου, 15:00 ώρα Ελλάδος.
Το link για το zoom είναι: https://ucph-ku.zoom.us/j/67586825824?p ... sveG9qZz09
Meeting ID: 675 8682 5824
Passcode: 988982
Μην ξεχάσετε να κατεβάσετε την εφαρμογή του zoom για να έχετε πρόσβαση στον ασπροπίνακα, καθώς η online έκδοση δε δίνει τέτοια δυνατότητα.
Τα λέμε τότε!
Re: Mηνιαία Πρόκληση: Ιανουάριος 2021
Να γράψω λύση ή να μη γράψω; Ιδού η απορία!
Πολλές φορές οι κώδικες που κυκλοφορούν για λύσεις σε προβλήματα διαγωνισμών και μη, είναι κατανοητοί μόνο από αυτούς που ... ξέρουν ήδη να λύσουν τα αντίστοιχα προβλήματα
Ένας κώδικας (ειδικά ενός διαγωνιζόμενου) είναι τόσο σύντομος και συχνά ακαταλαβίστικος και δεν βοηθά την κατανόηση της λύσης. Ο λόγος που γίνεται αυτό είναι γιατί ο λύτης έχει πιθανότατα χρησιμοποιήσει ένα σύνολο γνώσεων στη λύση του, με σκοπό το συντομότερο σε κώδικα ή πολυπλοκότητα αποτέλεσμα. Αυτές οι "ταρζανιές" μπορεί να αποθαρρύνουν τους νεαρούς μαθητές που δεν έχουν την ανάλογη γνώση και άνεση στο χειρισμό της γλώσσας, να ξέρετε όμως ότι αυτές οι ταρζανιές δεν είναι πάντα απαραίτητες και πολλές φορές με μοναδικό κόστος την αύξηση των γραμμών του κώδικα, μπορούν οι ίδιες λειτουργίες να γραφτούν πιο απλά.
Ας αρχίσουμε τη συζήτηση πάνω στο πρόβλημα μας. (ουφ, επιτέλους
)
Στο συγκεκριμένο πρόβλημα, η ύπαρξη δυο δρόμων είναι ένα κερασάκι στο γλυκό, είναι το επιδόρπιο και δεν χρειάζεται να μας απασχολεί παρά μόνο στο τέλος. Αρκεί να βρούμε τους συνδυασμούς για τον ΕΝΑ δρόμο και να τον υψώσουμε στο τετράγωνο. Αν έχουμε δηλαδή k συνδυασμούς για τον ένα δρόμο, τότε έχουμε άλλους k για τον άλλο. Πόσοι είναι οι συνδυασμοί και για τους δύο δρόμους; για κάθε έναν από τους k συνδυασμούς του ενός δρόμου, έχουμε k συνδυασμούς από τον άλλο δρόμο. Αρα για τους k συνδυασμούς του πρώτου δρόμου, έχουμε συνολικά k*k συνδυασμούς με τους δύο δρόμους μαζί.
Ας δούμε ποια είναι η αρχική ιδέα αν θέλουμε να λύσουμε το πρόβλημα με τον ένα δρόμο, όχι προσπαθώντας να ακολουθήσουμε το γνωστό τύπο για εύρεση του ν-οστού όρου της γνωστής ακολουθίας (ονόματα δε λέμε), αλλά με pure δυναμικό προγραμματισμό.
Ο δυναμικός προγραμματισμός είναι μια αξιοποίηση της επαγωγικής μεθόδου που διδάσκεται στο γυμνάσιο (αν δεν κάνω λάθος):
α) υπολογίζω την αρχική τιμή (για το μικρότερο δυνατό πρόβλημα, συνήθως ενός στοιχείου) και
β) υπολογίζω την τιμή για i+1 αν ξέρω ήδη την απάντηση για i στοιχεία.
Οπότε όπως καταλαβαίνετε εφόσον ξέρουμε την απάντηση για Ν==1 (από το (α)), μπορούμε να βρούμε το επόμενο για Ν==2 (από το (β)) και το επόμενο για Ν==3 (από το (β)) κλπ
Γραμμική λύση Ο(Ν):
α) αν έχουμε 1 τμήμα δρόμου, έχουμε μόνο δυο συνδυασμούς (building=κτήριο ή void=κενό)
β) ας υπολογίσουμε πόσοι συνδυασμοί θα υπάρχουν για k+1 τμήματα.
Για κάθε αριστερό κομμάτι δρόμου k τμημάτων, τότε θα προσθέσουμε ένα ακόμα τμήμα (και να πάμε στα k+1 τμήματα). Το νέο τμήμα αυτό αν θα είναι void, θα έχει όσους συνδυασμούς είχαμε για τα k τμήματα (ανεξάρτητα αν τελείωναν σε building ή void).
Αν το νέο τμήμα είναι building, θα έχουμε όσους συνδυασμούς είχαμε για τα k τμήματα και τελείωναν σε void.
Το άθροισμα των δυο τιμών είναι οι συνολικοί συνδυασμοί των k+1 τμημάτων.
Λογαριθμική λύση O(logN):
Στην προηγούμενη λύση, ανεβαίναμε ένα ένα τα τμήματα μέχρι να φτάσουμε στα Ν του προβλήματος. Οι γραμμικές λύσεις για Ν γύρω στο 10^6, απαιτούν περίπου 1 δευτερόλεπτο. Αν το N όμως είναι 2^63 (περίπου 10^19), δεν αρκεί η παραπάνω λύση. Για μεγάλα Ν πρέπει να σκαρφαλώνουμε πιο γρήγορα στο Ν.
Η διαφορά από την προηγούμενη (γραμμική) μέθοδο, είναι ότι θέλω να προσθέτω μπλοκ δρόμου με άλλο μπλοκ δρόμου (μπλοκ = δρόμος με ένα ή περισσότερα διαδοχικά τμήματα). Προφανώς για να ενώσουμε δύο μπλόκ δεν θα πρέπει το πρώτο μπλοκ να τελειώνει σε building και το δεύτερο να αρχίζει από building. Άρα πρέπει να κρατάμε ΧΩΡΙΣΤΑ για κάθε υπολογισμένο μπλοκ, πόσοι συνδυασμοί:
Μια σημείωση ακόμα στη συνένωση δυο μπλόκ: αν από το πρώτο μπλόκ είχαμε a συνδυασμούς από building σε void και από το δεύτερο μπλοκ b συνδυασμούς από building σε building, τότε στο συνενωμένο δρόμο θα πρέπει να προσθέσουμε άλλους a*b συνδυασμούς σε αυτούς που ξεκινούν από building και τελειώνουν σε building (γιατί για οποιοδήποτε συνδυασμό του πρώτου δρόμου από τους a, έχουμε b συνδυασμούς από τον δεύτερο δρόμο, άρα συνολικά a*b συνδυασμούς)
Μια λογαριθμική λύση είναι να διαιρώ το Ν δια δύο μέχρι να φτάσω στο 1 (top down programming: ξεκινάμε από το συνολικό πρόβλημα και κόβουμε συνεχώς σε μικρότερα).
(ΣΣ οποιοσδήποτε φυσικός αριθμός μπορεί να γραφτεί σαν άθροισμα δυνάμεων του 2, αυτό μάλιστα χρησιμοποιεί και η συνήθης τεχνολογία των υπολογιστών -μέχρι τώρα- για την αναπαράσταση αριθμών και την ονομάζουμε δυαδικό σύστημα).
Αρα προϋπολογίζουμε τους συνδυασμούς για 1,2,4,8,16,32,64,128,... (χωρίς να ξεπεράσουμε το Ν διότι δεν θα μας χρησιμεύσει).
Ποια μπλόκ θα συνδυάσουμε για τον Ν μήκους δρόμο;
Όσες από τις παραπάνω δυνάμεις του 2 έχουν άθροισμα ακριβώς Ν. Είναι δύσκολο αυτό να το βρούμε; Όχι βέβαια, αρκεί να δούμε την αναπαράσταση του Ν στο δυαδικό σύστημα.
π.χ. ο αριθμός Ν = 1000 (στο δεκαδικό σύστημα), είναι o 001111101000(στο δυαδικό)
Αν βρείτε λάθη έκφρασης στο κείμενο, sorry αλλά μετά από κάποιο χρόνο δεν γίνεται άλλο edit!

Πολλές φορές οι κώδικες που κυκλοφορούν για λύσεις σε προβλήματα διαγωνισμών και μη, είναι κατανοητοί μόνο από αυτούς που ... ξέρουν ήδη να λύσουν τα αντίστοιχα προβλήματα

Ένας κώδικας (ειδικά ενός διαγωνιζόμενου) είναι τόσο σύντομος και συχνά ακαταλαβίστικος και δεν βοηθά την κατανόηση της λύσης. Ο λόγος που γίνεται αυτό είναι γιατί ο λύτης έχει πιθανότατα χρησιμοποιήσει ένα σύνολο γνώσεων στη λύση του, με σκοπό το συντομότερο σε κώδικα ή πολυπλοκότητα αποτέλεσμα. Αυτές οι "ταρζανιές" μπορεί να αποθαρρύνουν τους νεαρούς μαθητές που δεν έχουν την ανάλογη γνώση και άνεση στο χειρισμό της γλώσσας, να ξέρετε όμως ότι αυτές οι ταρζανιές δεν είναι πάντα απαραίτητες και πολλές φορές με μοναδικό κόστος την αύξηση των γραμμών του κώδικα, μπορούν οι ίδιες λειτουργίες να γραφτούν πιο απλά.
Ας αρχίσουμε τη συζήτηση πάνω στο πρόβλημα μας. (ουφ, επιτέλους

Στο συγκεκριμένο πρόβλημα, η ύπαρξη δυο δρόμων είναι ένα κερασάκι στο γλυκό, είναι το επιδόρπιο και δεν χρειάζεται να μας απασχολεί παρά μόνο στο τέλος. Αρκεί να βρούμε τους συνδυασμούς για τον ΕΝΑ δρόμο και να τον υψώσουμε στο τετράγωνο. Αν έχουμε δηλαδή k συνδυασμούς για τον ένα δρόμο, τότε έχουμε άλλους k για τον άλλο. Πόσοι είναι οι συνδυασμοί και για τους δύο δρόμους; για κάθε έναν από τους k συνδυασμούς του ενός δρόμου, έχουμε k συνδυασμούς από τον άλλο δρόμο. Αρα για τους k συνδυασμούς του πρώτου δρόμου, έχουμε συνολικά k*k συνδυασμούς με τους δύο δρόμους μαζί.
Ας δούμε ποια είναι η αρχική ιδέα αν θέλουμε να λύσουμε το πρόβλημα με τον ένα δρόμο, όχι προσπαθώντας να ακολουθήσουμε το γνωστό τύπο για εύρεση του ν-οστού όρου της γνωστής ακολουθίας (ονόματα δε λέμε), αλλά με pure δυναμικό προγραμματισμό.
Ο δυναμικός προγραμματισμός είναι μια αξιοποίηση της επαγωγικής μεθόδου που διδάσκεται στο γυμνάσιο (αν δεν κάνω λάθος):
α) υπολογίζω την αρχική τιμή (για το μικρότερο δυνατό πρόβλημα, συνήθως ενός στοιχείου) και
β) υπολογίζω την τιμή για i+1 αν ξέρω ήδη την απάντηση για i στοιχεία.
Οπότε όπως καταλαβαίνετε εφόσον ξέρουμε την απάντηση για Ν==1 (από το (α)), μπορούμε να βρούμε το επόμενο για Ν==2 (από το (β)) και το επόμενο για Ν==3 (από το (β)) κλπ
Γραμμική λύση Ο(Ν):
α) αν έχουμε 1 τμήμα δρόμου, έχουμε μόνο δυο συνδυασμούς (building=κτήριο ή void=κενό)
β) ας υπολογίσουμε πόσοι συνδυασμοί θα υπάρχουν για k+1 τμήματα.
Για κάθε αριστερό κομμάτι δρόμου k τμημάτων, τότε θα προσθέσουμε ένα ακόμα τμήμα (και να πάμε στα k+1 τμήματα). Το νέο τμήμα αυτό αν θα είναι void, θα έχει όσους συνδυασμούς είχαμε για τα k τμήματα (ανεξάρτητα αν τελείωναν σε building ή void).
Αν το νέο τμήμα είναι building, θα έχουμε όσους συνδυασμούς είχαμε για τα k τμήματα και τελείωναν σε void.
Το άθροισμα των δυο τιμών είναι οι συνολικοί συνδυασμοί των k+1 τμημάτων.
Λογαριθμική λύση O(logN):
Στην προηγούμενη λύση, ανεβαίναμε ένα ένα τα τμήματα μέχρι να φτάσουμε στα Ν του προβλήματος. Οι γραμμικές λύσεις για Ν γύρω στο 10^6, απαιτούν περίπου 1 δευτερόλεπτο. Αν το N όμως είναι 2^63 (περίπου 10^19), δεν αρκεί η παραπάνω λύση. Για μεγάλα Ν πρέπει να σκαρφαλώνουμε πιο γρήγορα στο Ν.
Η διαφορά από την προηγούμενη (γραμμική) μέθοδο, είναι ότι θέλω να προσθέτω μπλοκ δρόμου με άλλο μπλοκ δρόμου (μπλοκ = δρόμος με ένα ή περισσότερα διαδοχικά τμήματα). Προφανώς για να ενώσουμε δύο μπλόκ δεν θα πρέπει το πρώτο μπλοκ να τελειώνει σε building και το δεύτερο να αρχίζει από building. Άρα πρέπει να κρατάμε ΧΩΡΙΣΤΑ για κάθε υπολογισμένο μπλοκ, πόσοι συνδυασμοί:
- ξεκινούν από void και τελειώνουν σε void και
- ξεκινούν από void και τελειώνουν σε building και
- ξεκινούν από building και τελειώνουν σε void και
- ξεκινούν από building και τελειώνουν σε building
Μια σημείωση ακόμα στη συνένωση δυο μπλόκ: αν από το πρώτο μπλόκ είχαμε a συνδυασμούς από building σε void και από το δεύτερο μπλοκ b συνδυασμούς από building σε building, τότε στο συνενωμένο δρόμο θα πρέπει να προσθέσουμε άλλους a*b συνδυασμούς σε αυτούς που ξεκινούν από building και τελειώνουν σε building (γιατί για οποιοδήποτε συνδυασμό του πρώτου δρόμου από τους a, έχουμε b συνδυασμούς από τον δεύτερο δρόμο, άρα συνολικά a*b συνδυασμούς)
Μια λογαριθμική λύση είναι να διαιρώ το Ν δια δύο μέχρι να φτάσω στο 1 (top down programming: ξεκινάμε από το συνολικό πρόβλημα και κόβουμε συνεχώς σε μικρότερα).
- Spoiler: show
(ΣΣ οποιοσδήποτε φυσικός αριθμός μπορεί να γραφτεί σαν άθροισμα δυνάμεων του 2, αυτό μάλιστα χρησιμοποιεί και η συνήθης τεχνολογία των υπολογιστών -μέχρι τώρα- για την αναπαράσταση αριθμών και την ονομάζουμε δυαδικό σύστημα).
Αρα προϋπολογίζουμε τους συνδυασμούς για 1,2,4,8,16,32,64,128,... (χωρίς να ξεπεράσουμε το Ν διότι δεν θα μας χρησιμεύσει).
Ποια μπλόκ θα συνδυάσουμε για τον Ν μήκους δρόμο;
Όσες από τις παραπάνω δυνάμεις του 2 έχουν άθροισμα ακριβώς Ν. Είναι δύσκολο αυτό να το βρούμε; Όχι βέβαια, αρκεί να δούμε την αναπαράσταση του Ν στο δυαδικό σύστημα.
π.χ. ο αριθμός Ν = 1000 (στο δεκαδικό σύστημα), είναι o 001111101000(στο δυαδικό)
- Spoiler: show
- Spoiler: show
- Spoiler: show
Αν βρείτε λάθη έκφρασης στο κείμενο, sorry αλλά μετά από κάποιο χρόνο δεν γίνεται άλλο edit!
