Problema rucsacului (de asemenea, problema rucsacului ) este o problemă de optimizare combinatorie NP-completă . Și-a luat numele de la scopul final: să pună cât mai multe lucruri de valoare într-un rucsac, cu condiția ca capacitatea ghiozdanului să fie limitată. Diferite variații ale problemei rucsacului pot fi întâlnite în economie , matematică aplicată , criptografie și logistică .
În general, problema poate fi formulată astfel: dintr-un set dat de articole cu proprietățile „cost” și „greutate”, este necesar să se selecteze un subset cu costul total maxim, cu respectarea restricției asupra greutății totale.
Să existe un set de obiecte, fiecare dintre ele având doi parametri - masa și valoarea. Există și un rucsac cu o anumită capacitate de transport. Sarcina este de a construi un rucsac cu valoarea maximă a obiectelor din interior, respectând în același timp limita de masă totală a rucsacului.
Matematic, problema este formulată astfel: există marfă. Pentru fiecare sarcină se determină masa și valoarea acesteia . Limita greutății totale a articolelor dintr-un rucsac este stabilită de capacitatea de transport . Necesar
maximiza cu restricţii şi [1] .Enunțul problemei permite un număr mare de generalizări, în funcție de condițiile impuse rucsacului, obiectelor sau alegerea acestora. Cele mai populare soiuri sunt următoarele:
Una dintre cele mai generale variante ale problemei rucsacului este cea neliniară . Poate fi formulat astfel:
Lăsați vectorul să determine numărul de instanțe ale fiecărui articol din rucsac. Atunci problema este să găsim minimul funcției
,
cu o constrângere dată:
.
Se presupune că funcțiile sunt continue și diferențiabile pe . este o constantă întreagă , mulțimea este nevide [7] .
În cazul funcțiilor liniare , problema se reduce la una din formulările clasice, în funcție de mulțime :
Libertatea în alegerea funcțiilor permite rezolvarea unei clase mai largi de sarcini, inclusiv organizarea instalațiilor de producție, distribuția optimă a probelor într-o probă regionalizată , sau soluția problemei rucsacului patratic [7] .
După cum am menționat mai sus, problema rucsacului aparține clasei NP-complete și până acum nu a fost găsit un algoritm polinomial pentru ea care să o rezolve într-un timp rezonabil. Prin urmare, atunci când se rezolvă problema rucsacului, este necesar să se aleagă între algoritmi exacti, care nu sunt aplicabili la rucsacuri „mari”, și cei aproximativi, care funcționează rapid, dar nu garantează soluția optimă a problemei.
Ca și în cazul altor probleme discrete , problema rucsacului poate fi rezolvată prin enumerarea exhaustivă a tuturor soluțiilor posibile.
În funcție de starea problemei, există articole care pot fi puse într-un rucsac și trebuie să determinați costul maxim al încărcăturii, a cărei greutate nu depășește .
Pentru fiecare articol, există 2 opțiuni: articolul este pus în rucsac, sau articolul nu este pus în rucsac. Atunci enumerarea tuturor opțiunilor posibile are complexitate de timp , ceea ce îi permite să fie utilizat doar pentru un număr mic de articole [8] . Odată cu creșterea numărului de obiecte, problema devine de nerezolvată prin această metodă într-un timp acceptabil.
Figura prezintă un arbore de iterație pentru trei elemente. Fiecare frunză corespunde unui subset de articole. După alcătuirea arborelui, este necesar să se găsească o frunză cu valoarea maximă dintre cele a căror greutate nu depășește [9] .
Metoda ramurilor și legate este o variație a metodei forței brute, cu diferența că ramurile neoptimale ale arborelui forței brute sunt excluse. La fel ca metoda forței brute, vă permite să găsiți soluția optimă și, prin urmare, aparține algoritmilor exacti.
Algoritmul original, propus de Peter Kolesar în 1967, propune sortarea articolelor după costul lor unitar (raportul dintre valoare și greutate) și construirea unui arbore cu forță brută . Îmbunătățirea sa constă în faptul că în procesul de construire a unui arbore pentru fiecare nod se estimează o limită superioară a valorii soluției, iar construcția arborelui continuă doar pentru nodul cu estimarea maximă [10] . Când limita superioară maximă este într-o frunză a arborelui, algoritmul își încheie activitatea.
Capacitatea de ramificare și legat de a reduce numărul de iterații se bazează în mare măsură pe datele de intrare. Este recomandabil să îl utilizați numai dacă valorile specifice ale articolelor diferă semnificativ [11] .
Cu o constrângere suplimentară asupra greutăților articolelor, problema rucsacului poate fi rezolvată în timp pseudopolinom folosind metode de programare dinamică .
Fie ponderea fiecărui element un număr întreg pozitiv. Apoi, pentru a rezolva problema, este necesar să se calculeze soluțiile optime pentru toate , unde este capacitatea de încărcare dată. Să definim ca fiind valoarea maximă a articolelor care pot fi plasate într-un rucsac cu o capacitate de transport de .
Pentru că puteți scrie formule recursive :
unde sunt valoarea și , respectiv, greutatea elementului --lea, iar maximul din setul gol ar trebui considerat egal cu zero.
De fapt, ultima ecuație este ecuația funcțională a lui R. Bellman sau ecuația funcțională a programării dinamice. În acest caz, pentru a o rezolva, este suficient să calculați toate valorile lui , începând de la și până la [12] . Dacă în plus stocăm la fiecare pas un set de articole care realizează valoarea maximă, atunci algoritmul va oferi și setul optim de articole.
Deoarece la fiecare pas este necesar să se găsească maximul itemilor, algoritmul are o complexitate de calcul de . Deoarece poate depinde exponențial de dimensiunea intrării, algoritmul este pseudopolinom . Prin urmare, eficiența acestui algoritm este determinată de valoarea lui . Algoritmul dă rezultate excelente pentru , dar nu foarte bune pentru [13] .
Problemă la rucsac 0-1Soluția problemei rucsacului 0-1 este aproape de soluția problemei anterioare, dar este necesar să se țină cont de faptul că fiecare articol se află într-un singur exemplar. Fie valoarea maximă a articolelor obținute din primele articole disponibile, cu o greutate totală care nu depășește .
Calculând , puteți găsi soluția exactă. Dacă matricea se potrivește în memoria mașinii, atunci acest algoritm este probabil unul dintre cele mai eficiente [12] .
// Intrare: // Valorile articolului (încărcate în matricea v) // Greutăți articole (încărcate în matricea w) // Număr de articole (n) // Capacitate de încărcare (W) pentru j de la 0 la W fac : m [ 0 , j ] := 0 pentru i de la 1 la n fac : pentru j de la 0 la W fac : dacă w [ i ] > j atunci : m [ i , j ] := m [ i -1 , j ] altceva : m [ i , j ] := max ( m [ i -1 , j ], m [ i -1 , j - w [ i ]] + v [ i ])Soluția poate fi ilustrată prin programare dinamică după cum urmează: pe un plan bidimensional, numărul de obiecte este reprezentat de-a lungul axei , iar greutatea lor este reprezentată de-a lungul axei. La prima etapă se construiesc două linii de la originea coordonatelor: una orizontală, corespunzătoare faptului că nu a fost luat primul obiect, și una înclinată, corespunzătoare primului obiect luat. Proiecțiile lor pe axă sunt egale cu greutatea obiectului. La a doua etapă se construiesc din nou 2 linii, orizontale (al doilea obiect nu a fost luat) sau oblice (al doilea obiect a fost luat). Să setăm lungimea arcelor orizontale la zero, iar lungimea arcelor oblice la valoarea obiectului [14] . Astfel, orice soluție a problemei corespunde unei căi în arborele construit . Problema se reduce la găsirea unei căi de lungime maximă [14] . Lăsați capacitatea rucsacului .
Numărul de articol | Valoare | Greutatea |
---|---|---|
unu | 3 | 5 |
2 | 5 | zece |
3 | patru | 6 |
patru | 2 | 5 |
Din figură se poate observa că valoarea totală pentru soluția optimă este 7, deoarece aceasta este valoarea maximă din arborele construit.
Programare dinamică asupra valorilor articolelorRelațiile de recurență pot fi scrise nu numai în ceea ce privește greutatea obiectelor, ci și în ceea ce privește valoarea. Pentru a face acest lucru, notăm ponderea minimă a articolelor cu valoarea totală , care poate fi obținută de la primele articole. Dacă greutatea necesară nu poate fi obținută, marcați-o ca .
După aceea, rezolvăm ecuația de programare dinamică funcțională :
,
cu conditiile initiale :
Ca și în cazul majorității problemelor NP-complete, nu este întotdeauna necesar să se obțină o soluție exactă, deoarece soluțiile care sunt aproape de optime pot fi aplicate în probleme aplicate.
Pentru a rezolva problema cu un algoritm lacom , este necesar să sortați lucrurile după valoarea lor specifică (adică raportul dintre valoarea unui articol și greutatea acestuia) și să plasați articolele cu cea mai mare valoare specifică în rucsac [10] .
Timpul de rulare al acestui algoritm este suma timpului de sortare și timpul de stivuire. Complexitatea sortării articolelor este de . Apoi, calculează câte articole vor încăpea în rucsac în timpul total [10] . Complexitatea rezultată atunci când sortarea este necesară și când datele sunt deja sortate [10] .
Exemplu . Lăsați capacitatea rucsacului . Articolele sunt deja sortate după valoarea unitară. Să folosim algoritmul lacom.
i | greutatea | Preț | pret/greutate |
---|---|---|---|
unu | cincisprezece | 60 | patru |
2 | treizeci | 90 | 3 |
3 | cincizeci | 100 | 2 |
Punem primul articol în rucsac, iar după el al doilea. Al treilea articol nu va intra în rucsac. Valoarea totală a articolelor din rucsac este de 150. Dacă s-ar lua al doilea și al treilea articol, valoarea totală ar fi 190. Astfel, am obținut o soluție neoptimală.
Trebuie înțeles că un algoritm lacom poate duce la un răspuns arbitrar departe de cel optim. De exemplu, dacă un articol are o pondere de 1 și un cost de 2, iar celălalt are o pondere de W și un cost de W, atunci algoritmul lacom va nota un cost total de 2 cu un răspuns optim de W. La în același timp, același algoritm pentru problema rucsacului nemărginit va conduce la un răspuns de cel puțin 50% din valoarea optimului [10] .
Algoritmul greedy a fost propus pentru prima dată de George Danzig [16] pentru a rezolva problema nemărginită a rucsacului.
Deoarece nu a fost găsit algoritmul exact pentru rezolvarea problemei în timp polinomial , problema a apărut pentru a obține o soluție polinomială cu precizie garantată . Pentru a face acest lucru, există o serie de scheme aproximative de timp complet polinom , adică cu complexitate care este un polinom în și .
Ideea din spatele schemei clasice este de a reduce precizia cu care sunt date valorile articolelor. Combinând articole de valoare similară într-un singur grup, puteți reduce numărul de articole diferite. Algoritmul se scrie astfel [15] :
Există multe scheme diferite de aproximare. Cu toate acestea, ele depind puternic de formularea problemei rucsacului. De exemplu, dacă în condiție apare o a doua constrângere de tip inegalitate (rucsac bidimensional), atunci problema nu mai are o schemă de timp polinomială cunoscută [17] .
Ca și în cazul altor probleme de optimizare NP-hard, algoritmii genetici sunt utilizați pentru a rezolva problema rucsacului . Nu garantează găsirea soluției optime în timp polinomial și nu oferă o estimare a proximității soluției față de cea optimă, dar au indicatori buni de timp, permițându-vă să găsiți o soluție destul de bună mai rapid decât alte deterministe sau euristice cunoscute. metode. [optsprezece]
Fiecare individ ( genotip ) este un subset al articolelor pe care dorim să le împachetăm în ghiozdan (greutatea lor totală poate depăși capacitatea de transport admisă). Pentru comoditate, informațiile sunt stocate ca șiruri binare, în care fiecare bit determină dacă acest articol se potrivește într-un ghiozdan [19] .
Funcția de fitness determină apropierea soluției de cea optimă. De exemplu, valoarea totală a articolelor poate servi ca atare, cu condiția ca greutatea totală să nu depășească capacitatea de transport.
După o serie de schimbări generaționale în care cei mai apți indivizi sunt încrucișați , iar restul sunt ignorați, algoritmul ar trebui să îmbunătățească soluțiile originale [19] .
Rezolvarea problemei sumei submulțimiiUn caz special al problemei rucsacului 0-1 este problema sumei subsetului . Fie capacitatea de transport a rucsacului, greutatea celui de-al -lea articol și costul acestuia . Astfel, sarcina este să încărcați rucsacul cât mai strâns posibil sau să epuizați complet resursele:
Pentru a o rezolva, puteți folosi algoritmul genetic menționat . Un individ este un vector . Ca funcție de fitness, ar trebui să se folosească proximitatea greutății totale a obiectelor de , cu singura caracteristică că seturile care se potrivesc într-un rucsac sunt mai de preferat (greutatea totală a obiectelor este mai mică de ) [19] .
Să definim formal funcția de fitness . Fie suma greutăților tuturor articolelor. Apoi - abaterea maximă posibilă a greutății articolelor din rucsac de la .
Fie greutatea totală a elementelor pentru vectorul dat. Apoi punem:
[19]
Folosind algoritmul general, putem găsi o soluție aproximativă:
Execuția este întreruptă fie când se găsește o soluție, fie după un număr dat de iterații [19] .
Nu se știe cu siguranță cine a fost primul care a dat formularea matematică a problemei rucsacului. Una dintre primele referiri la acesta poate fi găsită într-un articol al lui George Ballard Matthews[20] [21] din 1897. Studiul intens al acestei probleme a început după publicarea de către D. B. Dantzig în 1957 a cărții „ Engleză. Discrete Variable Extremum Problem » [22] , mai ales în anii 70-90 ai secolului XX, atât de către teoreticieni, cât și de către practicieni [2] . În multe privințe, interesul a fost cauzat de o formulare destul de simplă a problemei, un număr mare de varietăți și proprietăți ale acesteia și, în același timp, de complexitatea soluției lor. În 1972, această problemă a fost inclusă în lista de probleme NP-complete a lui M. Karp ( articolul în limba engleză „Reducibility Among Combinatorial Problems” ) [23] .
O interpretare vizuală a problemei rucsacului a dus la faptul că aceasta și-a găsit aplicație în diverse domenii ale cunoașterii: în matematică, informatică și, la intersecția acestor științe, în criptografie . Într-una din lucrările de lingvistică computațională [24] , se propune formularea problemei rezumarii automate a textelor , un caz special al căruia corespunde formulării problemei rucsacului.
Pe baza problemei rucsacului, a fost creat primul algoritm de criptare asimetrică . Ideea criptografiei cu cheie publică a fost prezentată pentru prima dată de Whitfield Diffie și Martin Hellman la Conferința Națională a Calculatoarelor din 1976 [25] [26] .
De asemenea, problema rucsacului poate servi drept model pentru un număr mare de probleme industriale [2] [27] :
În 1978, Ralph Merkle și Martin Hellman au dezvoltat primul algoritm pentru criptarea generalizată a cheilor publice , criptosistemul Merkle-Hellman , bazat pe problema rucsacului. Au publicat versiuni cu o singură etapă (în engleză cu repetare unică ) și cu mai multe etape (în engleză cu repetare multiplă ), iar algoritmul a putut fi folosit doar pentru criptare. Dar Adi Shamir l-a adaptat pentru utilizare în semnăturile digitale [28] .
Ulterior, au fost propuse și alte criptosisteme bazate pe problema rucsacului, dintre care unele sunt o modificare a criptosistemului Merkle-Hellman. Criptosisteme cunoscute [29] :
Datorită faptului că problema generală a rucsacului nu poate fi rezolvată exact într-un timp rezonabil, poate fi folosită în probleme criptografice . Pentru a face acest lucru, cu un set de articole cunoscut public, vom reprezenta mesajul ca un set de articole transmise și vom trimite greutatea totală a acestora [28] .
Definiție. Un vector rucsac este un set ordonat de n articole, unde este greutatea celui de-al -lea articol [30] .
Vectorul rucsac este o cheie publică . Pentru a cripta textul simplu, acesta este împărțit în blocuri cu lungimea de biți, fiecare bit determinând prezența unui articol în rucsac (de exemplu, textul simplu corespunde prezenței primelor patru din șase articole posibile în rucsac). Se crede că unul indică prezența unui articol în rucsac, iar zero indică absența acestuia [28] .
După aceea, greutatea totală a articolelor din rucsac pentru textul simplu dat este calculată și transmisă ca text cifrat [28] .
Un exemplu de criptare cu acest algoritm:
Să fie dat un vector rucsac cu lungime .
text simplu | 1 1 1 1 1 0 | 0 0 1 1 0 0 | 0 0 0 0 0 0 | 0 0 0 0 0 1 |
---|---|---|---|---|
Lucruri în rucsac | 3 4 6 7 10 | 6 7 | unsprezece | |
Text cifrat | 3 + 4 + 6 + 7 + 10 = 30 | 6 + 7 = 13 | 0 | unsprezece |
Problema rucsacului | |
---|---|
Aplicații | |
Criptosisteme bazate pe problema rucsacului |
|
În plus |
Probleme NP-complete | |
---|---|
Problema de maximizare a stivuirii (ambalării) |
|
teoria grafurilor teoria multimelor | |
Probleme algoritmice | |
Jocuri de logică și puzzle-uri | |