0/1 Σακίδιο Διόρθωση Προβλήματος με χρήση του Παραδείγματος Δυναμικού Προγραμματισμού

⚡ Έξυπνη Σύνοψη

Το πρόβλημα σακιδίου 0/1 χρησιμοποιεί Δυναμικό Προγραμματισμό για να επιλέξει από ένα σύνολο σταθμισμένων, αξιολογημένων πακέτων, έτσι ώστε το συνολικό βάρος να παραμένει εντός μιας χωρητικότητας M, ενώ η συνολική τιμή να φτάσει στη μέγιστη δυνατή.

  • 🎒 Πρόβλημα: Δεδομένων n στοιχείων, το καθένα με βάρος W[i] και τιμή V[i], επιλέξτε ένα υποσύνολο που ταιριάζει στην χωρητικότητα M και μεγιστοποιεί τη συνολική τιμή χωρίς να διαιρέσει κανένα στοιχείο.
  • 🧮 Επανάληψη: B[i][j] = max(B[i-1][j], V[i] + B[i-1][j – W[i]]) καταγράφει την επιλογή παραλαβής ή παράλειψης για κάθε στοιχείο και χωρητικότητα.
  • 🧱 Πίνακας από κάτω προς τα πάνω: Ένα πλέγμα (n+1) μέσω (M+1) αποθηκεύει απαντήσεις σε υποπροβλήματα, επομένως καμία εργασία δεν επαναλαμβάνεται ποτέ σε αναδρομικές κλήσεις.
  • 🔍 TracΗλεκτρονική Επιστροφή: Η ανάγνωση του πίνακα από το B[n][M] μέχρι τη γραμμή 0 ανακτά ακριβώς ποια πακέτα έλαβε η βέλτιστη λύση.
  • Περίπλοκο: Χρόνος O(n·M) και χώρος O(n·M), καθιστώντας τον αλγόριθμο ψευδοπολυωνυμικό και ακατάλληλο όταν το M είναι εκθετικό.
  • 🚀 Χρήσεις: Η φόρτωση φορτίου, η κατανομή του προϋπολογισμού, η κρυπτογραφία, ο προγραμματισμός πόρων και η επιλογή χαρακτηριστικών που βασίζεται στην τεχνητή νοημοσύνη βασίζονται όλα στο 0/1 Knapsack.

0/1 Πρόβλημα Σακιδίου Δυναμικός Προγραμματισμός

Τι είναι το πρόβλημα του σακιδίου;

The Πρόβλημα με σακίδιο είναι ένα κλασικό πρόβλημα συνδυαστικής βελτιστοποίησης. Ένα σούπερ μάρκετ n συσκευασίες (n ≤ 100). Συσκευασία i έχει βάρος W[i] ≤ 100 και τιμή V[i] ≤ 100. Ένας κλέφτης δεν μπορεί να μεταφέρει βάρος που υπερβαίνει τη χωρητικότητα M (M ≤ 100). Ποια δέματα πρέπει να πάρει ο κλέφτης για να μεγιστοποιήσει τη συνολική αξία;

εισόδου:

  • Μέγιστο βάρος M και αριθμός συσκευασιών n.
  • Πίνακας βάρους W[i] και αντίστοιχης τιμής V[i].

Παραγωγή:

  • Μέγιστη συνολική τιμή που μπορεί να επιτευχθεί εντός της χωρητικότητας.
  • Το ακριβές σύνολο δεμάτων που πρέπει να πάρει ο κλέφτης.

Ο αλγόριθμος Knapsack χωρίζεται σε δύο γνωστές παραλλαγές:

  • 0/1 Πρόβλημα με το Σακίδιο λύνεται με Δυναμικό Προγραμματισμό. Κάθε πακέτο είτε λαμβάνεται ολόκληρο είτε αφήνεται πίσω — χωρίς κλασματικά κομμάτια και χωρίς διπλότυπα.
  • Πρόβλημα κλασματικού σακιδίου λύνεται με μια Άπληστη Στρατηγική. Εδώ μπορείτε να πάρετε ένα κλάσμα οποιουδήποτε πακέτου για να γεμίσετε την υπόλοιπη χωρητικότητα.

Πώς να λύσετε το πρόβλημα του σακιδίου χρησιμοποιώντας το δυναμικό προγραμματισμό με Παράδειγμα

Η μέθοδος «διαίρει και βασίλευε» διαιρεί ένα μεγάλο πρόβλημα σε υποπροβλήματα και στη συνέχεια συνεχίζει να διαιρεί το πρόβλημα μέχρι να γίνει εύκολο κάθε υποπρόβλημα. Η απλή αναδρομή, ωστόσο, συχνά λύνει το ίδιο υποπρόβλημα πολλές φορές και σπαταλάει δουλειά.

Η βασική ιδέα του Δυναμικού Προγραμματισμού Knapsack είναι η αποθήκευση κάθε λυμένου υποπροβλήματος σε έναν πίνακα. Οι επαναλαμβανόμενες κλήσεις διαβάζουν την απάντηση αντί να την υπολογίζουν ξανά, μετατρέποντας μια εκθετική αναδρομή σε κώδικα πολυωνυμικού χρόνου.

Επίλυση Προβλήματος Σακιδίου χρησιμοποιώντας Δυναμικό Προγραμματισμό

Επίλυση Προβλήματος Σακιδίου χρησιμοποιώντας Δυναμικό Προγραμματισμό

Για να σχεδιάσετε μια λύση Δυναμικού Προγραμματισμού, ακολουθείτε τέσσερα βήματα:

  • Λύστε πρώτα τα μικρότερα υποπροβλήματα.
  • Παράγετε μια επαναλαμβανόμενη απάντηση που δομεί μια υπο-προβληματική απάντηση από μικρότερα.
  • Αποθηκεύστε τις απαντήσεις των υποπροβλημάτων σε έναν πίνακα που υπολογίζεται από κάτω προς τα πάνω χρησιμοποιώντας την επαναληπτικότητα.
  • Συγκεντρώστε την τελική απάντηση από τον πλήρως συμπληρωμένο πίνακα.

Αναλύστε το πρόβλημα του σακιδίου 0/1

Η βέλτιστη τιμή εξαρτάται από δύο ανεξάρτητους παράγοντες:

  1. Πόσα πακέτα εξετάζονται ακόμη.
  2. Το υπόλοιπο βάρος μπορεί ακόμα να χωρέσει το σακίδιο.

Επειδή η αντικειμενική συνάρτηση εξαρτάται από δύο ποσότητες, ο πίνακας επιλογών πρέπει να είναι δισδιάστατος. Έστω B[i][j] δηλώνει τη μέγιστη τιμή κατά την επιλογή μεταξύ συσκευασιών {1, …, i} με όριο βάρους j.

  • Η τελική απάντηση είναι B[n][M], η καλύτερη συνολική τιμή σε όλα τα n πακέτα με χωρητικότητα M.
  • Το συνολικό επιλεγμένο βάρος περιορίζεται πάντα από την τρέχουσα χωρητικότητα: B[i][j] ≤ j.

Παράδειγμα: εάν B[4][10] = 8, το καλύτερο συνολικό βάρος από τα πρώτα τέσσερα δέματα κάτω από τη χωρητικότητα 10 είναι 8. Μερικά από αυτά τα τέσσερα δέματα ενδέχεται να παραλειφθούν.

Τύπος για τον υπολογισμό του B[i][j]

  • W[i], V[i] είναι το βάρος και η αξία του πακέτου i, όπου το i βρίσκεται στο {1, …, n}.
  • M είναι το μέγιστο βάρος που μπορεί να μεταφέρει ένα σακίδιο πλάτης.

Βασική περίπτωση με ένα πακέτο: για κάθε χωρητικότητα j ≥ W[1]:

B[1][j] = W[1]

Για τη γενική περίπτωση, αποφασίστε εάν θα συμπεριλάβετε το πακέτο i στην χωρητικότητα j:

  • Αν το πακέτο i είναι παραλείφθηκε, B[i][j] ισούται με την καλύτερη τιμή χρησιμοποιώντας πακέτα {1, …, i-1} υπό χωρητικότητα j:
B[i][j] = B[i - 1][j]
  • Αν το πακέτο i είναι λαμβάνεται (επιτρέπεται μόνο όταν W[i] ≤ j), B[i][j] ισούται με V[i] συν την καλύτερη τιμή από τα πακέτα {1, …, i-1} υπό χωρητικότητα j – W[i]:
B[i][j] = V[i] + B[i - 1][j - W[i]]

Πάρτε τον μεγαλύτερο από τους δύο υποψηφίους.

Βάση Δυναμικού Προγραμματισμού

Ο συνδυασμός των δύο περιπτώσεων δίνει την πλήρη επανάληψη:

B[i][j] = max(B[i - 1][j], V[i] + B[i - 1][j - W[i]])

Η βασική περίπτωση είναι B[0][j] = 0 για κάθε j, επειδή τα μηδενικά πακέτα δίνουν μηδενική τιμή ανεξάρτητα από τη χωρητικότητα.

Υπολογίστε τον Πίνακα Επιλογών

Δημιουργήστε το B χρησιμοποιώντας την επαναλαμβανόμενη διαδικασία. Μόλις συμπληρωθεί το B, ο ίδιος πίνακας οδηγεί το trace-back που ανακατασκευάζει τα επιλεγμένα πακέτα. Ο Πίνακας Β έχει n + 1 γραμμές και M + 1 στήλες:

  • Η σειρά 0 είναι η βασική περίπτωση, γεμάτη με μηδενικά.
  • Χρησιμοποιήστε τη γραμμή 0 για να υπολογίσετε τη γραμμή 1, τη γραμμή 1 για να υπολογίσετε τη γραμμή 2 και συνεχίστε μέχρι να ολοκληρωθεί η γραμμή n.

Υπολογίστε τον Πίνακα Επιλογών

Πίνακας Επιλογών

Trace

Μόλις ολοκληρωθεί το Β, επικεντρωθείτε στο B[n][M], η βέλτιστη συνολική τιμή σε όλα τα n πακέτα με χωρητικότητα M.

  • If Β[n][M] = Β[n-1][M], το πακέτο n δεν επιλέχθηκε, οπότε συνεχίστε tracαπό B[n-1][M].
  • If Β[n][M] ≠ Β[n-1][M], επιλέχθηκε το πακέτο n, άρα συνεχίστε tracαπό B[n-1][M – W[n]].

Επαναλάβετε μέχρι να φτάσετε στη σειρά 0 του πίνακα.

Αλγόριθμος για την αναζήτηση του πίνακα επιλογών για την εύρεση των επιλεγμένων πακέτων

Σημείωση: όποτε B[i][j] = B[i-1][j], το πακέτο i δεν είναι επιλεγμένο. Η τιμή B[n][M] είναι η βέλτιστη συνολική τιμή που συσκευάζεται στο σακίδιο.

Βήματα για tracτα επιλεγμένα πακέτα:

  • Βήμα 1: Ξεκινήστε από i = n, j = M.
  • Βήμα 2: Σαρώστε τη στήλη j από κάτω προς τα πάνω μέχρι να βρείτε μια γραμμή i όπου B[i][j] > B[i-1][j]. Σημειώστε το πακέτο i ως επιλεγμένο: Select[i] = true.
  • Βήμα 3: Ενημερώστε το j = j – W[i]. Αν j > 0, επιστρέψτε στο Βήμα 2, διαφορετικά προχωρήστε στο Βήμα 4.
  • Βήμα 4: Εκτυπώστε κάθε πακέτο που έχει επισημανθεί ως επιλεγμένο.

Java Code

Ο ακόλουθος Java η μέθοδος συμπληρώνει το B[][] από κάτω προς τα πάνω, εκτυπώνει τον πίνακα για έλεγχο και, στη συνέχεια, tracτα επιλεγμένα πακέτα.

public void knapsackDyProg(int W[], int V[], int M, int n) {
    int B[][] = new int[n + 1][M + 1];

    for (int i = 0; i <= n; i++)
        for (int j = 0; j <= M; j++) {
            B[i][j] = 0;
        }

    for (int i = 1; i <= n; i++) {
        for (int j = 0; j <= M; j++) {
            B[i][j] = B[i - 1][j];

            if ((j >= W[i - 1]) && (B[i][j] < B[i - 1][j - W[i - 1]] + V[i - 1])) {
                B[i][j] = B[i - 1][j - W[i - 1]] + V[i - 1];
            }

            System.out.print(B[i][j] + " ");
        }
        System.out.print("\n");
    }

    System.out.println("Max Value:\t" + B[n][M]);
    System.out.println("Selected Packs: ");

    int j = M;
    while (n != 0) {
        if (B[n][j] != B[n - 1][j]) {
            System.out.println("\tPackage " + n + " with W = " + W[n - 1] + " and Value = " + V[n - 1]);
            j = j - W[n - 1];
        }
        n--;
    }
}

Λειτουργία knapsackDyProg() σε Java

Λειτουργία knapsackDyProg() σε Java

Επεξήγηση του κώδικα:

  1. Κατανομή πίνακα B[][] και αρχικοποιήστε κάθε κελί στο 0.
  2. Συμπληρώστε το B[][] από κάτω προς τα πάνω χρησιμοποιώντας την επανάληψη από την προηγούμενη ενότητα.
  3. Ξεκινήστε κάθε κελί με την τιμή «παράλειψη πακέτου i» B[i-1][j].
  4. Εάν η επιλογή του πακέτου i είναι εφικτή και δίνει μια αυστηρά καλύτερη τιμή, αντικαταστήστε το κελί.
  5. Tracμεταφέρετε τα επιλεγμένα στοιχεία από τη σειρά n πίσω στη σειρά 0.
  6. Όποτε επιλέγεται το πακέτο n, μειώνεται η υπολειπόμενη χωρητικότητα κατά W[n-1].

Σημείωση διόρθωσης: η παράμετρος μεταλλαγμένου αρχικού αποσπάσματος M ενώ ακόμα διαβάζω B[n][M]Η ασφαλέστερη έκδοση παραπάνω χρησιμοποιεί ξεχωριστό κέρσορα j των trace.

The Java Ο οδηγός εκτελεί τον αλγόριθμο σε δύο επεξεργασμένα παραδείγματα:

public void run() {
    // First Example
    // int W[] = new int[]{3, 4, 5, 9, 4};
    // int V[] = new int[]{3, 4, 4, 10, 4};
    // int M = 11;

    // Second Example
    int W[] = new int[]{12, 2, 1, 1, 4};
    int V[] = new int[]{4, 2, 1, 2, 10};
    int M = 15;

    int n = V.length;
    knapsackDyProg(W, V, M, n);
}

Έξοδος για το πρώτο παράδειγμα:

0 0 0 3 3 3 3 3 3 3 3 3
0 0 0 3 4 4 4 7 7 7 7 7
0 0 0 3 4 4 4 7 7 8 8 8
0 0 0 3 4 4 4 7 7 10 10 10
0 0 0 3 4 4 4 7 8 10 10 11
Max Value:	11
Selected Packs:
	Package 5 with W = 4 and Value = 4
	Package 2 with W = 4 and Value = 4
	Package 1 with W = 3 and Value = 3

Έξοδος για το δεύτερο παράδειγμα:

0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4
0 0 2 2 2 2 2 2 2 2 2 2 4 4 6 6
0 1 2 3 3 3 3 3 3 3 3 3 4 5 6 7
0 2 3 4 5 5 5 5 5 5 5 5 5 6 7 8
0 2 3 4 10 12 13 14 15 15 15 15 15 15 15 15
Max Value:	15
Selected Packs:
	Package 5 with W = 4 and Value = 10
	Package 4 with W = 1 and Value = 2
	Package 3 with W = 1 and Value = 1
	Package 2 with W = 2 and Value = 2

Χρονική και χωρική πολυπλοκότητα του σακιδίου πλάτης 0/1

  • Χρονική πολυπλοκότητα: O(n · M) — οι δύο ένθετοι βρόχοι σαρώνουν n στοιχεία σε καταστάσεις χωρητικότητας M+1.
  • Πολυπλοκότητα χώρου: O(n · M) για τον πλήρη πίνακα, αναγώγιμο σε O(M) από το keeping μόνο η προηγούμενη σειρά όταν tracΔεν απαιτείται ηλεκτρονική επιστροφή.

Ο χρόνος εκτέλεσης είναι ψευδο-πολυώνυμο: πολυωνυμικό στην τιμή του M αλλά εκθετικό στα bits που χρησιμοποιούνται για την κωδικοποίηση του M. Αυτός είναι ο λόγος για τον οποίο το 0/1 Knapsack παραμένει NP-hard παρόλο που ο Δυναμικός Προγραμματισμός είναι αποτελεσματικός στην πράξη.

Εφαρμογές του προβλήματος του σακιδίου πλάτης 0/1

  • Φόρτωση φορτίου, συσκευασία εμπορευματοκιβωτίων και παραλαβή από την αποθήκη εντός ορίων βάρους.
  • Κατανομή προϋπολογισμού σε επενδυτικά έργα με σταθερό κόστος και αναμενόμενη απόδοση.
  • Προβλήματα μείωσης αποθεμάτων στην κατασκευή που δεν μπορούν να διαχωρίσουν μεμονωμένα κομμάτια.
  • Σχήματα κρυπτογραφίας όπως το Merkle-Hellman που βασίζονται στη σκληρότητα του σακιδίου πλάτης.
  • Χρονοπρογραμματισμός με περιορισμούς πόρων στο cloud computing και τοποθέτηση εργασιών CPU.
  • Επιλογή χαρακτηριστικών στη μηχανική μάθηση με σταθερό προϋπολογισμό χαρακτηριστικών.

Συχνές Ερωτήσεις

Το 0/1 Knapsack επιλέγει ένα υποσύνολο σταθμισμένων, αξιολογημένων αντικειμένων, έτσι ώστε το συνολικό βάρος να παραμένει εντός της χωρητικότητας M, ενώ η συνολική αξία να μεγιστοποιείται. Κάθε αντικείμενο είτε αφαιρείται ολόκληρο είτε παραλείπεται.

Το πρόβλημα έχει επικάλυψηping Υποπροβλήματα και βέλτιστη υποδομή. Ο Δυναμικός Προγραμματισμός αποθηκεύει κάθε απάντηση υποπροβλήματος μία φορά, επομένως η αναδρομή καταρρέει από εκθετικό σε πολυωνυμικό χρόνο O(n πολλαπλασιασμένο επί M).

Το πρόβλημα του σακιδίου πλάτης 0/1 απαιτεί ολόκληρα αντικείμενα και λύνεται με Δυναμικό Προγραμματισμό. Κλασματικό σακίδιο πλάτης επιτρέπει τον τεμαχισμό αντικειμένων και επιλύεται από έναν άπληστο αλγόριθμο που επιλέγει πρώτα την υψηλότερη αναλογία αξίας προς βάρος.

Ναι. Το 0/1 Knapsack είναι NP-hard. Ο Δυναμικός Προγραμματισμός εκτελείται σε χρόνο O(n πολλαπλασιασμένο επί M), ο οποίος είναι ψευδο-πολυωνυμικός. Ο χρόνος εκτέλεσης είναι πολυωνυμικός στην τιμή του M αλλά εκθετικός στον αριθμό των bit που χρησιμοποιούνται για την κωδικοποίηση του M.

Ναι. Όταν χρειάζεστε μόνο τη μέγιστη τιμή και όχι τα επιλεγμένα πακέτα, διατηρήστε μόνο την προηγούμενη γραμμή του πίνακα. Αυτό μειώνει τη μνήμη από O(n πολλαπλασιασμένο με M) σε O(M) ενώ ο χρόνος εκτέλεσης παραμένει ο ίδιος.

Η φόρτωση φορτίου, η κατανομή του προϋπολογισμού, η μείωση του αποθέματος, η κρυπτογραφία, ο προγραμματισμός πόρων cloud και η επιλογή χαρακτηριστικών μηχανικής μάθησης μειώνονται στο 0/1 Knapsack. Οποιοδήποτε πρόβλημα συσκευασίας με σταθερή χωρητικότητα και αδιαίρετα είδη είναι πιθανό.

Οι ευρετικές μεθόδους μηχανικής μάθησης και ενισχυτικής μάθησης υπερτερούν του ακριβούς Δυναμικού Προγραμματισμού όταν το M είναι τεράστιο. Τα δίκτυα δεικτών και τα νευρωνικά δίκτυα γραφημάτων προβλέπουν επίσης επιλογές στοιχείων σε πολύ μεγάλες βιομηχανικές περιπτώσεις.

Ναι. Το GitHub Copilot ενσωματώνει τον πίνακα DP, την επανάληψη και το tracηλεκτρονική επιστροφή Java, PythonΤο HIFU, ή Υψηλής Έντασης Εστιασμένος Υπέρηχος, στοχεύει επίσης στο πρόσωπο και τον λαιμό. Προσφέρει θεραπεία σε γρήγορες εκπομπές, γεγονός που κάνει τις συνεδρίες θεραπείας συντομότερες. C++και δημιουργεί δοκιμές μονάδας που ελέγχουν τόσο τη μέγιστη τιμή όσο και τα επιλεγμένα πακέτα.

Συνοψίστε αυτήν την ανάρτηση με: