update: lees hier over het optimaliseren van de ruimtecomplexiteit van de dynamische programmeeroplossing in mijn vervolgartikel.,
Het Knapzak-probleem is een heel interessant probleem in de combinatoriek-om Wikipedia aan te halen, bepaalt
“gegeven een verzameling items, elk met een gewicht en een waarde, het aantal van elk item dat in een verzameling moet worden opgenomen, zodat het totale gewicht kleiner is dan of gelijk is aan een bepaalde limiet en de totale waarde zo groot mogelijk is.”
van Wikipedia zien we dat er een paar variaties zijn van het Knapzak probleem: 0-1 knapzak, bounded knapzak, en unbounded knapzak., Vandaag richten we ons op de meest voorkomende (en eenvoudigste) variatie: het 0-1 ranselprobleem.
een iets interessantere en meer relateerbare frasering van het 0-1 knapzak probleem is:
beschouw een dief krijgt in een huis om te beroven en hij draagt een ranpack. Er zijn vast aantal items in het huis-elk met zijn eigen gewicht en waarde — sieraden, met minder gewicht en hoogste waarde vs tafels, met minder waarde, maar veel zwaar. Om brandstof aan het vuur toe te voegen, heeft de dief een oude ransel met beperkte capaciteit., Hij kan de tafel niet in tweeën splitsen of sieraden in 3/4. Hij neemt het of laat het achter. Source
helaas had ik moeite met het begrijpen van sommige delen van het Hackerearth artikel, daarom besloot ik mijn eigen artikel te schrijven. Dit artikel zal grotendeels worden gebaseerd op artikel Hackerearth ‘ s en code fragmenten zijn geschreven in Java. Ik zal aanvullende verklaringen en uitwerkingen volgen waar ik denk dat ze nodig zijn.
We zullen dit probleem oplossen met dynamisch programmeren., Dynamisch programmeren vereist een optimale onderstructuur en overlappende subproblemen, die beide aanwezig zijn in het 0-1 ranselprobleem, zoals we zullen zien.
Het is prima als je niet begrijpt wat “optimale substructuur” en “overlappende subproblemen” zijn (dat is een artikel voor een andere dag). In wezen betekent het gewoon een bepaalde smaak van problemen die ons in staat stellen om eerdere oplossingen voor kleinere problemen te hergebruiken om een oplossing voor het huidige probleem te berekenen. Je zult zien wat ik bedoel.,
Probleemdetails
aangezien dit het 0-1 knapzak-probleem is, kunnen we een item in onze ransel opnemen of uitsluiten, maar er geen fractie van opnemen, of het meerdere keren opnemen.
oplossing
eerst maken we een 2-dimensionale array (d.w.z. een tabel) van n + 1
rijen en w + 1
kolommen.
een rijnummer i vertegenwoordigt de verzameling van alle items uit rijen 1-i. bijvoorbeeld, de waarden in rij 3 gaan ervan uit dat we alleen items 1, 2 en 3 hebben.
een kolomnummer j staat voor het gewicht van onze ransel., Daarom gaan de waarden in kolom 5 er bijvoorbeeld van uit dat onze ransel 5 gewichtseenheden kan bevatten.
alles samenvoegen, een item in rij i, kolom j vertegenwoordigt de maximale waarde die kan worden verkregen met de items 1, 2, 3 … i, in een rugzak die j gewichtseenheden kan bevatten.
laten we onze tabel mat
voor matrix aanroepen. Daarom is int mat = new int
.
Stap 2:
We kunnen onmiddellijk beginnen met het invullen van enkele regels in onze tabel: de basiscases, waarvoor de oplossing triviaal is., Bijvoorbeeld, bij rij 0, wanneer we geen items hebben om uit te kiezen, moet de maximale waarde die in een ransel kan worden opgeslagen 0 zijn. Evenzo, bij kolom 0, voor een ransel die 0 gewichtseenheden kan bevatten, is de maximale waarde die erin kan worden opgeslagen 0. (We gaan ervan uit dat er geen massaloze, waardevolle items.)
We kunnen dit doen met 2 voor loops: