0/1 Knapsekkproblemfiks ved hjelp av dynamisk programmeringseksempel

โšก Smart oppsummering

0/1 Ryggsekkproblemet bruker dynamisk programmering til รฅ velge fra et sett med vektede, verdsatte pakker, slik at totalvekten holder seg innenfor en kapasitet M mens totalverdien nรฅr maksimalt mulig nivรฅ.

  • ๐ŸŽ’ problem: Gitt n elementer hver med vekt W[i] og verdi V[i], velg et delsett som passer til kapasitet M og maksimerer totalverdien uten รฅ splitte noen elementer.
  • ๐Ÿงฎ Tilbakefall: B[i][j] = max(B[i-1][j], V[i] + B[i-1][j โ€“ W[i]]) registrerer ta-eller-hopp-valget for hver vare og kapasitet.
  • ๐Ÿงฑ Nederst-opp-tabell: Et (n+1) x (M+1) rutenett lagrer svar pรฅ delproblemer, slik at ingen arbeid noen gang gjentas pรฅ tvers av rekursive kall.
  • ๐Ÿ” Trace-Tilbake: ร… lese tabellen fra B[n][M] og opp til rad 0 gjenoppretter nรธyaktig hvilke pakker den optimale lรธsningen tok.
  • ๏ธ kompleksitet: Tid O(nยทM) og rom O(nยทM), noe som gjรธr algoritmen pseudo-polynomisk og uegnet nรฅr M er eksponensiell.
  • ๐Ÿš€ Bruksomrรฅder: Lasting av last, budsjettallokering, kryptografi, ressursplanlegging og AI-drevet funksjonsvalg er alle avhengige av 0/1 Knapsack.

0/1 Ryggsekkproblem Dynamisk programmering

Hva er ryggsekkproblemet?

Ocuco Rullesekk problem er et klassisk kombinatorisk optimaliseringsproblem. Et supermarked lager n pakker (n โ‰ค 100). Pakke i har vekt W[i] โ‰ค 100 og verdi V[i] โ‰ค 100. En tyv kan ikke bรฆre vekt som overstiger kapasiteten M (M โ‰ค 100). Hvilke pakker bรธr tyven ta for รฅ maksimere den totale verdien?

Inngang:

  • Maksimal vekt M og antall pakker n.
  • Array av vekt W[i] og tilsvarende verdi V[i].

Utgang:

  • Maksimal totalverdi oppnรฅelig innenfor kapasiteten.
  • Det nรธyaktige settet med pakker tyven bรธr ta.

Knapsack-algoritmen deler seg inn i to kjente varianter:

  • 0/1 Ryggsekkproblem lรธses med dynamisk programmering. Hver pakke tas enten hel eller blir liggende igjen โ€“ ingen brรธkdeler og ingen duplikater.
  • Problem med brรธksekk lรธst med en grรฅdig strategi. Her kan du ta en brรธkdel av en pakke for รฅ fylle den gjenvรฆrende kapasiteten.

Hvordan lรธse Knapsack-problem ved hjelp av dynamisk programmering med eksempel

Del-og-hersk-metoden deler et stort problem inn i delproblemer, og fortsetter deretter รฅ dele opp til hvert delproblem er enkelt. Ren rekursjon lรธser imidlertid ofte det samme delproblemet mange ganger og er slรธsing med arbeid.

Kjerneideen bak dynamisk programmering i Knapsack er รฅ lagre alle lรธste delproblemer i en tabell. Gjentatte kall leser svaret i stedet for รฅ beregne det pรฅ nytt, og gjรธr dermed en eksponensiell rekursjon om til polynomisk tidskode.

Lรธs Knapsack-problem ved hjelp av dynamisk programmering

Lรธs Knapsack-problem ved hjelp av dynamisk programmering

For รฅ designe en dynamisk programmeringslรธsning fรธlger du fire trinn:

  • Lรธs de minste delproblemene fรธrst.
  • Utled en rekursjon som bygger et delproblemsvar fra mindre regelmessigheter.
  • Lagre svar pรฅ delproblemer i en tabell beregnet nedenfra og opp ved hjelp av gjentakelsen.
  • Sett sammen det endelige svaret fra den fullstendig utfylte tabellen.

Analyser 0/1 ryggsekkproblemet

Den optimale verdien avhenger av to uavhengige faktorer:

  1. Hvor mange pakker er fortsatt under vurdering?
  2. Den gjenvรฆrende vekten kan ryggsekken fortsatt lagre.

Fordi objektivfunksjonen er avhengig av to stรธrrelser, mรฅ tabellen med alternativer vรฆre todimensjonal. La B[i][j] betegner maksimumsverdien nรฅr man velger mellom pakker {1, โ€ฆ, i} med vektgrense j.

  • Det endelige svaret er B[n][M], den beste totalverdien pรฅ tvers av alle n pakker under kapasitet M.
  • Den totale valgte vekten er alltid begrenset av gjeldende kapasitet: B[i][j] โ‰ค j.

Eksempel: hvis B[4][10] = 8, er den beste totalvekten fra de fire fรธrste pakkene under kapasitet 10 8. Noen av disse fire pakkene kan hoppes over.

Formel for รฅ beregne B[i][j]

  • W[i], V[i] er vekten og verdien av pakke i, hvor i er i {1, โ€ฆ, n}.
  • M er den maksimale vekten sekken kan bรฆre.

Basistilfelle med รฉn pakke: for hver kapasitet j โ‰ฅ W[1]:

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

For det generelle tilfellet, avgjรธr om pakke i skal inkluderes under kapasitet j:

  • Hvis pakke i er hoppet, B[i][j] er lik den beste verdien ved bruk av pakker {1, โ€ฆ, i-1} under kapasitet j:
B[i][j] = B[i - 1][j]
  • Hvis pakke i er tatt (kun tillatt nรฅr W[i] โ‰ค j), B[i][j] er lik V[i] pluss den beste verdien fra pakkene {1, โ€ฆ, i-1} under kapasitet j โ€“ W[i]:
B[i][j] = V[i] + B[i - 1][j - W[i]]

Ta den stรธrste av de to kandidatene.

Grunnlag for dynamisk programmering

ร… kombinere de to tilfellene gir full gjentakelse:

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

Basistilfellet er B[0][j] = 0 for hver j, fordi null pakker gir null verdi uavhengig av kapasitet.

Beregn alternativtabellen

Bygg B ved hjelp av gjentakelsen. Nรฅr B er fylt, driver den samme tabellen trace-back som rekonstruerer de valgte pakkene. Tabell B har n + 1 rader og M + 1 kolonner:

  • Rad 0 er basistilfellet, fylt med nuller.
  • Bruk rad 0 til รฅ beregne rad 1, rad 1 til รฅ beregne rad 2, og fortsett til rad n er fullfรธrt.

Beregn alternativtabellen

Tabell over alternativer

Trace

Nรฅr B er ferdig, fokuser pรฅ B[n][M], den optimale totalverdien pรฅ tvers av alle n pakker med kapasitet M.

  • If B[n][M] = B[n-1][M], pakke n ble ikke valgt, sรฅ fortsett tracfra B[n-1][M].
  • If B[n][M] โ‰  B[n-1][M], pakke n ble valgt, sรฅ fortsett tracfra B[n-1][M โ€“ W[n]].

Gjenta til du kommer til rad 0 i tabellen.

Algoritme for รฅ slรฅ opp alternativtabellen for รฅ finne de valgte pakkene

Merk: nรฅr som helst B[i][j] = B[i-1][j], pakke i er ikke valgt. Verdien B[n][M] er den optimale totalverdien pakket i ryggsekken.

Trinn for tracde valgte pakkene:

  • Trinn 1: Start ved i = n, j = M.
  • Trinn 2: Skann kolonne j nedenfra og opp til du finner en rad i der B[i][j] > B[i-1][j]. Merk pakke i som valgt: Select[i] = true.
  • Trinn 3: Oppdater j = j โ€“ W[i]. Hvis j > 0, gรฅ tilbake til trinn 2, ellers gรฅ til trinn 4.
  • Trinn 4: Skriv ut alle pakker som er merket som valgt.

Java Code

Fรธlgende Java metoden fyller B[][] nedenfra og opp, skriver ut tabellen for inspeksjon, og deretter tracde valgte pakkene.

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--;
    }
}

Funksjon knapsackDyProg() i Java

Funksjon knapsackDyProg() i Java

Forklaring av koden:

  1. Tildel tabell B[][] og initialiser hver celle til 0.
  2. Fyll B[][] nedenfra og opp ved รฅ bruke gjentakelsen fra forrige avsnitt.
  3. Start hver celle med verdien ยซhopp over pakke iยป B[i-1][j].
  4. Hvis det er mulig รฅ velge pakke i og gir en strengt tatt bedre verdi, overskriv cellen.
  5. TracFlytt de valgte elementene fra rad n tilbake til rad 0.
  6. Nรฅr pakke n velges, reduser den gjenvรฆrende kapasiteten med W[n-1].

Rettingsmerknad: den opprinnelige kodebitens muterte parameter M mens de fortsatt leser B[n][M]Den sikrere versjonen ovenfor bruker en separat markรธr. j for trace.

Ocuco Java driveren kjรธrer algoritmen pรฅ to utarbeidede eksempler:

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);
}

Utdata for det fรธrste eksemplet:

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

Utdata for det andre eksemplet:

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

Tids- og romkompleksiteten til 0/1 ryggsekk

  • Tidskompleksitet: O(n ยท M) โ€” de to nestede lรธkkene feier n elementer over M+1 kapasitetstilstander.
  • Romkompleksitet: O(n ยท M) for hele tabellen, reduserbar til O(M) ved keeping bare forrige rad nรฅr trace-back er ikke nรธdvendig.

Kjรธretiden er pseudo-polynom: polynom i verdien av M, men eksponensiell i bitene som brukes til รฅ kode M. Det er derfor 0/1 Knapsack forblir NP-hard selv om dynamisk programmering er effektivt i praksis.

Anvendelser av 0/1-ryggsekkproblemet

  • Lasting av gods, pakking av containere og plukking pรฅ lager under vektbegrensninger.
  • Budsjettfordeling pรฅ tvers av investeringsprosjekter med faste kostnader og forventet avkastning.
  • Problemer med lagerbeholdning i produksjonen som ikke kan dele individuelle deler.
  • Kryptografiske ordninger som Merkle-Hellman som bygger pรฅ ryggsekkhardhet.
  • Ressursbegrenset planlegging i skytjenester og plassering av CPU-oppgaver.
  • Funksjonsvalg i maskinlรฆring under et fast funksjonsbudsjett.

Spรธrsmรฅl og svar

0/1 Ryggsekken velger et delsett av vektede, verdsatte gjenstander, slik at totalvekten holder seg innenfor kapasitet M mens totalverdien maksimeres. Hver gjenstand tas enten hel eller utelates.

Problemet har overlappingping Delproblemer og optimal delstruktur. Dynamisk programmering lagrer svaret pรฅ hvert delproblem รฉn gang, slik at rekursjonen kollapser fra eksponensiell til polynomisk tid O(n multiplisert med M).

0/1 Ryggsekk krever hele gjenstander og lรธses ved dynamisk programmering. Fraksjonell ryggsekk tillater oppdeling av elementer og lรธses av en grรฅdig algoritme som velger det hรธyeste verdi-til-vekt-forholdet fรธrst.

Ja. 0/1 Knapsack er NP-hard. Dynamisk programmering kjรธrer i O(n multiplisert med M) tid, som er pseudo-polynomisk. Kjรธretiden er polynomisk i verdien av M, men eksponentiell i antall bits som brukes til รฅ kode M.

Ja. Nรฅr du bare trenger den maksimale verdien og ikke de valgte pakkene, beholder du bare den forrige raden i tabellen. Det reduserer minnet fra O(n multiplisert med M) ned til O(M), mens kjรธretiden forblir den samme.

Lasting av last, budsjettallokering, kutting av varer, kryptografi, planlegging av skyressurser og valg av maskinlรฆringsfunksjoner reduseres til 0/1 Knapsack. Ethvert pakkeproblem med fast kapasitet og udelelige varer er en kandidat.

Maskinlรฆrings- og forsterkningslรฆringsheuristikker slรฅr eksakt dynamisk programmering nรฅr M er enorm. Pekernettverk og grafiske nevrale nettverk forutsier ogsรฅ elementvalg pรฅ svรฆrt store industrielle instanser.

Ja. GitHub Copilot bruker stillasene for DP-tabellen, gjentakelsen og trace-tilbake inn Java, Pythoneller C++, og genererer enhetstester som sjekker bรฅde maksimumsverdien og de valgte pakkene.

Oppsummer dette innlegget med: