<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://www.algopedia.ro/wiki/index.php?action=history&amp;feed=atom&amp;title=Rucsac</id>
	<title>Rucsac - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://www.algopedia.ro/wiki/index.php?action=history&amp;feed=atom&amp;title=Rucsac"/>
	<link rel="alternate" type="text/html" href="https://www.algopedia.ro/wiki/index.php?title=Rucsac&amp;action=history"/>
	<updated>2026-04-13T03:30:09Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.44.2</generator>
	<entry>
		<id>https://www.algopedia.ro/wiki/index.php?title=Rucsac&amp;diff=18125&amp;oldid=prev</id>
		<title>Bella at 21:00, 28 March 2021</title>
		<link rel="alternate" type="text/html" href="https://www.algopedia.ro/wiki/index.php?title=Rucsac&amp;diff=18125&amp;oldid=prev"/>
		<updated>2021-03-28T21:00:26Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;Note de curs Clasa a 11-a , Dinamica, Isabela Coman&lt;br /&gt;
= Problema Rucsacului =&lt;br /&gt;
Considerăm un set de &amp;#039;&amp;#039;&amp;#039;n&amp;#039;&amp;#039;&amp;#039; obiecte, fiecare fiind caracterizat de un volum ( dimensiune ) &amp;#039;&amp;#039;&amp;#039;vol&amp;#039;&amp;#039;&amp;#039; și de o valoare &amp;#039;&amp;#039;&amp;#039;val&amp;#039;&amp;#039;&amp;#039;, și un rucsac cu un volum &amp;#039;&amp;#039;&amp;#039;G&amp;#039;&amp;#039;&amp;#039;. Să se selecteze un subset de obiecte astfel încât volumul total al obiectelor selectate să fie &amp;lt;= &amp;#039;&amp;#039;&amp;#039;G&amp;#039;&amp;#039;&amp;#039; iar valoarea totală a obiectelor selectate să fie maximă.&lt;br /&gt;
Variante:&lt;br /&gt;
* Varianta continuă (fracționară): pot fi selectate obiecte in întregime &amp;#039;&amp;#039;&amp;#039;sau fracțiuni&amp;#039;&amp;#039;&amp;#039; ale obiectelor.&lt;br /&gt;
* Varianta discretă(0-1): obiectele pot fi selectate doar în întregime&lt;br /&gt;
&lt;br /&gt;
 Exemplu: n = 3, G = 5,&lt;br /&gt;
 vol   1   2   3&lt;br /&gt;
 val   6  10  12&lt;br /&gt;
 unit  6   5   4 &lt;br /&gt;
 &lt;br /&gt;
Pentru Varianta Fractionara &amp;#039;&amp;#039;&amp;#039;Tehnica Greedy&amp;#039;&amp;#039;&amp;#039; ne poate da solutia problemei:&lt;br /&gt;
* Se sortează lista de obiecte descrescător după valoarea pe unitatea de volum unit = val / dim&lt;br /&gt;
* Se selectează obiectele în această ordine până când nu mai încap elemente in rucsac. Daca am obtinut un volum egal cu volumul Ruxacului, atunci am obtinut solutia finala. Altfel, vom lua din urmatorul obiect o fractiune, pentru a completa volumul Ruxacului.&lt;br /&gt;
&lt;br /&gt;
Astfel, pentru exemplul de mai sus, pentru a umple ruscacul de dimensiune 5, vom selecta primele 2 obiecte si 2 unitati din obiectul al treilea, de volum 3.&lt;br /&gt;
solutia va fi: ( 1, 1, 2/3 ) - obtinem valoarea: 6 + 10 + 8 = 24&lt;br /&gt;
&lt;br /&gt;
Pentru Varianta discreta Tehnica Greedy nu ne va da solutia optima. Conform acestei tehnici, vom pune in rucsac primele 2 obiecte, obtinand solutia: &lt;br /&gt;
* solutia ( 1, 1, 0 )  Alegem primele 2 obiecte care ocupa un volum = 3 si obtinem o valoare de: 6 + 10 = 16&lt;br /&gt;
O solutie mai buna ar fi:&lt;br /&gt;
* solutia (0, 1, 1 ) - Alegem ultimele 2 obiecte care ocupa un volum = 5 si obtinem o valoare de: 10 + 12 = 22&lt;br /&gt;
&lt;br /&gt;
===Problema Rucsacului - Varianta discretă(0-1) ===&lt;br /&gt;
Problema rucsacului poate fi reformulată astfel: se caută (s&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;,s&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt;,…,s&amp;lt;sub&amp;gt;n&amp;lt;/sub&amp;gt;) cu s&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; in {0,1} astfel încât:&lt;br /&gt;
 * s&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;*d&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt; +…+ s&amp;lt;sub&amp;gt;n&amp;lt;/sub&amp;gt;*d&amp;lt;sub&amp;gt;n&amp;lt;/sub&amp;gt; &amp;lt;= C (restricție)&lt;br /&gt;
 * s&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;*v&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt; +…+ s&amp;lt;sub&amp;gt;n&amp;lt;/sub&amp;gt;*v&amp;lt;sub&amp;gt;n&amp;lt;/sub&amp;gt;  este maximă (criteriu de optim)&lt;br /&gt;
Vectorul &amp;#039;&amp;#039;&amp;#039;s&amp;#039;&amp;#039;&amp;#039; descrie ce elemente sunt selectate, astfel incat valoarea lor sa fie maxima, &amp;lt;= C&lt;br /&gt;
&lt;br /&gt;
[[file:Rucsac0_1.png|600px]]&lt;br /&gt;
&lt;br /&gt;
====Varianta iterativa - bottom up ====&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;lt;fstream&amp;gt;&lt;br /&gt;
using namespace std;&lt;br /&gt;
const int NMAX = 1000;             // nr maxim de obiecte&lt;br /&gt;
const int GMAX = 10000;&lt;br /&gt;
&lt;br /&gt;
int a[NMAX+1][GMAX+1];&lt;br /&gt;
int n, G, g;                       // nr obiectelor, capacitatea rucsacului&lt;br /&gt;
int vol[NMAX+1], val[NMAX+1];&lt;br /&gt;
int main() {&lt;br /&gt;
  cin &amp;gt;&amp;gt; n &amp;gt;&amp;gt; G;&lt;br /&gt;
  for( int i = 1; i &amp;lt;= n; i++ )&lt;br /&gt;
    cin &amp;gt;&amp;gt; vol[i] &amp;gt;&amp;gt; val[i];&lt;br /&gt;
&lt;br /&gt;
  for( int i = 1; i &amp;lt;= n; i++ )&lt;br /&gt;
    for( int j = 1; j &amp;lt;= G; j++ ) {&lt;br /&gt;
      if ( j &amp;lt; vol[i] )&lt;br /&gt;
        a[i][j] = a[i-1][j];&lt;br /&gt;
      else&lt;br /&gt;
        a[i][j] = max ( a[i-1][j], a[i-1][j-vol[i]] + val[i] );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  for( int i = 0; i &amp;lt;= n; i++ ){&lt;br /&gt;
    for( int j = 0; j &amp;lt;= G; j++ )&lt;br /&gt;
      cout &amp;lt;&amp;lt; a[i][j] &amp;lt;&amp;lt; &amp;quot; &amp;quot;;&lt;br /&gt;
    cout &amp;lt;&amp;lt; &amp;#039;\n&amp;#039;;&lt;br /&gt;
  }&lt;br /&gt;
  cout &amp;lt;&amp;lt; a[n][G] &amp;lt;&amp;lt; &amp;#039;\n&amp;#039;;           //   val maxima obtinua&lt;br /&gt;
&lt;br /&gt;
  //ce obiecte am selectat?&lt;br /&gt;
  int sol[NMAX+1] = {0};&lt;br /&gt;
  int i = n;&lt;br /&gt;
  int j = G;&lt;br /&gt;
  while ( j ){&lt;br /&gt;
    if ( a[i][j] != a[i-1][j] ) {&lt;br /&gt;
      sol[i] = 1;              // elem i e selectat&lt;br /&gt;
      j = j - vol[i];          // ne ducem pe col volumului ramas&lt;br /&gt;
    }&lt;br /&gt;
    i --;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for( int i = 1; i &amp;lt;= n; i++ )&lt;br /&gt;
    if (sol[i])&lt;br /&gt;
      cout &amp;lt;&amp;lt; i &amp;lt;&amp;lt; &amp;quot; &amp;quot;;&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
/*&lt;br /&gt;
3 5&lt;br /&gt;
1 6&lt;br /&gt;
2 10&lt;br /&gt;
3 12&lt;br /&gt;
*/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Varianta recursiva top-down + Memoizare ====&lt;br /&gt;
Pt a construi soluția sunt suficiente doar valorile marcate. Numărul calculelor poate fi redus dacă&lt;br /&gt;
se calculează doar valorile necesare construcției solutiei. Acest lucru se poate realiza prin&lt;br /&gt;
îmbinarea abordării descendente cu cea ascendentă (cu reținerea valorilor calculate). Aceasta este denumita tehnica memoizării.&lt;br /&gt;
* Abordarea ascendentă clasică (prezentata anterior )rezolvă toate subproblemele (chiar și cele care nu contribuie la soluția optimă) însă fiecare problemă este rezolvată o singură dată.&lt;br /&gt;
* Abordarea descendentă ( recursiva ) clasică rezolvă doar subproblemele ce contribuie la soluția problemei însă o subproblemă este rezolvată de câte ori apare (din acest motiv implementarea recursivă este în general ineficientă)&lt;br /&gt;
&lt;br /&gt;
Tehnica memoizării rezolvă o singură dată doar subproblemele ce contribuie la soluția problemei&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Etape:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* Se inițializează matrice cu o valoare diferita de orice valoare s-ar obține prin dezvoltarea relației de recurență, pentru a marca faptul ca o valorile nu sunt inca calculate.&lt;br /&gt;
* Se calculează valoarea țintă a[n,G] în manieră recursivă însă toate valorile intermediare se stochează și se utilizează atunci când e necesar. &lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;lt;fstream&amp;gt;&lt;br /&gt;
#define D 0&lt;br /&gt;
using namespace std;&lt;br /&gt;
const int NMAX = 1000;             // nr maxim de obiecte&lt;br /&gt;
const int GMAX = 10000;&lt;br /&gt;
&lt;br /&gt;
int a[NMAX+1][GMAX+1];&lt;br /&gt;
int n, G, g;                       // nr obiectelor, capacitatea rucsacului&lt;br /&gt;
int vol[NMAX+1], val[NMAX+1];&lt;br /&gt;
&lt;br /&gt;
int comp ( int i, int j ){&lt;br /&gt;
  if ( i == 0 || j == 0 ) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
  if ( a[i][j] != -1 )     // daca val e deja calculata, o returnam&lt;br /&gt;
    return a[i][j];&lt;br /&gt;
  int x = comp( i-1, j );    // daca nu as avea comp i-1 in sol&lt;br /&gt;
  if ( j &amp;lt; vol[i] )&lt;br /&gt;
    a[i][j] = x;&lt;br /&gt;
  else&lt;br /&gt;
    a[i][j] = max ( x, comp( i-1, j-vol[i]) + val[i] );&lt;br /&gt;
  return a[i][j];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
  cin &amp;gt;&amp;gt; n &amp;gt;&amp;gt; G;&lt;br /&gt;
  for( int i = 1; i &amp;lt;= n; i++ )&lt;br /&gt;
    cin &amp;gt;&amp;gt; vol[i] &amp;gt;&amp;gt; val[i];&lt;br /&gt;
&lt;br /&gt;
  for( int i = 1; i &amp;lt;= n; i++ )&lt;br /&gt;
    for( int j = 1; j &amp;lt;= G; j++ ) {&lt;br /&gt;
      a[i][j] = -1;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  cout &amp;lt;&amp;lt; comp(n,G) &amp;lt;&amp;lt; &amp;#039;\n&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
  if ( D ){&lt;br /&gt;
    for( int i = 0; i &amp;lt;= n; i++ ){&lt;br /&gt;
      for( int j = 0; j &amp;lt;= G; j++ )&lt;br /&gt;
        cout &amp;lt;&amp;lt; a[i][j] &amp;lt;&amp;lt; &amp;quot; &amp;quot;;&lt;br /&gt;
      cout &amp;lt;&amp;lt; &amp;#039;\n&amp;#039;;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  //ce obiecte am selectat?&lt;br /&gt;
  int sol[NMAX+1] = {0};&lt;br /&gt;
  int i = n;&lt;br /&gt;
  int j = G;&lt;br /&gt;
  while ( j ){&lt;br /&gt;
    if ( a[i][j] != a[i-1][j] ) {&lt;br /&gt;
      sol[i] = 1;              // elem i e selectat&lt;br /&gt;
      j = j - vol[i];          // ne ducem pe col volumului ramas&lt;br /&gt;
    }&lt;br /&gt;
    i --;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for( int i = 0; i &amp;lt;= n; i++ )&lt;br /&gt;
    if (sol[i])&lt;br /&gt;
      cout &amp;lt;&amp;lt; i &amp;lt;&amp;lt; &amp;quot; &amp;quot;;&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
/*&lt;br /&gt;
3 5&lt;br /&gt;
1 6&lt;br /&gt;
2 10&lt;br /&gt;
3 12&lt;br /&gt;
*/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Optimizarea memoriei utilizate in varianta iterativa Bottom-up ====&lt;br /&gt;
In solutia iterativa, putem observa ca pentru o anumita linie din dinamica, recurenta nu se foloseste decat de linia precedenta, deci retinerea intregului tablou este inutila, in cazul in care trebuie sa calculam doar valoarea maxima a rucsacului. Putem sa reţinem doar o singura linie, dacă parcurgem linia în sensul invers al greutăţilor. &lt;br /&gt;
[https://www.infoarena.ro/problema/rucsac rucsac varena]&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;lt;fstream&amp;gt;&lt;br /&gt;
#define D 0&lt;br /&gt;
using namespace std;&lt;br /&gt;
const int NMAX = 5000;             // nr maxim de obiecte&lt;br /&gt;
const int GMAX = 10000;&lt;br /&gt;
ifstream fin(&amp;quot;rucsac.in&amp;quot;);&lt;br /&gt;
ofstream fout(&amp;quot;rucsac.out&amp;quot;);&lt;br /&gt;
int a[GMAX+1];&lt;br /&gt;
int n, G, g;                       // nr obiectelor, capacitatea rucsacului&lt;br /&gt;
int vol[NMAX+1], val[NMAX+1];&lt;br /&gt;
int main() {&lt;br /&gt;
  fin &amp;gt;&amp;gt; n &amp;gt;&amp;gt; G;&lt;br /&gt;
  for( int i = 1; i &amp;lt;= n; i++ )&lt;br /&gt;
    fin &amp;gt;&amp;gt; vol[i] &amp;gt;&amp;gt; val[i];&lt;br /&gt;
&lt;br /&gt;
  for( int i = 1; i &amp;lt;= n; i++ ) {&lt;br /&gt;
    for( int j = G; j &amp;gt;= vol[i]; j-- ) {&lt;br /&gt;
      a[j] = max ( a[j], a[j-vol[i]] + val[i] );&lt;br /&gt;
    }&lt;br /&gt;
   if ( D ) {&lt;br /&gt;
     for( int j = 1; j &amp;lt;= G; j++ )&lt;br /&gt;
        cout &amp;lt;&amp;lt; a[j] &amp;lt;&amp;lt; &amp;quot; &amp;quot;;&lt;br /&gt;
     cout &amp;lt;&amp;lt; &amp;#039;\n&amp;#039;;&lt;br /&gt;
   }&lt;br /&gt;
  }&lt;br /&gt;
  fout &amp;lt;&amp;lt; a[G] &amp;lt;&amp;lt; &amp;#039;\n&amp;#039;;           //   val maxima obtinua&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Aplicatii =&lt;br /&gt;
&lt;br /&gt;
===[https://www.varena.ro/problema/rucsac rucsac varena]===&lt;br /&gt;
Se citesc doua numere naturale N si K si un sir v de N numere naturale. Sa se raspunda la urmatoarea intrebare:&lt;br /&gt;
Cate subsiruri ale sirului initial au suma elementelor egala cu K?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;lt;fstream&amp;gt;&lt;br /&gt;
#define MOD 999979&lt;br /&gt;
using namespace std;&lt;br /&gt;
const int NMAX = 500;             // nr maxim de obiecte&lt;br /&gt;
const int GMAX = 250000;&lt;br /&gt;
ifstream fin(&amp;quot;rucsac.in&amp;quot;);&lt;br /&gt;
ofstream fout(&amp;quot;rucsac.out&amp;quot;);&lt;br /&gt;
int a[GMAX+1];&lt;br /&gt;
int vol;&lt;br /&gt;
int n, G;                       // nr obiectelor, capacitatea rucsacului&lt;br /&gt;
int main() {&lt;br /&gt;
  fin &amp;gt;&amp;gt; n &amp;gt;&amp;gt; G;&lt;br /&gt;
&lt;br /&gt;
  a[0] = 1;                     &lt;br /&gt;
  for( int i = 1; i &amp;lt;= n; i++ ) {&lt;br /&gt;
    fin &amp;gt;&amp;gt; vol;&lt;br /&gt;
    for( int j = G; j &amp;gt;= vol; j-- )&lt;br /&gt;
      if (a[j-vol]) {&lt;br /&gt;
        a[j] += a[j-vol];&lt;br /&gt;
        a[j] %= MOD;&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fout &amp;lt;&amp;lt; a[G] &amp;lt;&amp;lt; &amp;#039;\n&amp;#039;;           //   val maxima obtinua&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===[https://www.pbinfo.ro/probleme/1959/rucsac-halloween rucsac-halloween]===&lt;br /&gt;
Sabin merge la colindat de Halloween. Ştiind ca poate colinda la n case, iar la fiecare primeşte g[1], g[2], ..., g[n] bomboane, iar în rucsacul lui încap G bomboane, aflaţi numărul minim de case pe care trebuie să le colinde Sabin pentru a umple ghiozdanul. Daca nu poate umple ghiozdanul, se afiseaza mesajul &amp;quot;NU&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Solutie O(n) memorie ===&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;lt;fstream&amp;gt;&lt;br /&gt;
using namespace std;&lt;br /&gt;
const int NMAX = 1000;        // nr maxim de obiecte&lt;br /&gt;
const int GMAX = 10000;&lt;br /&gt;
int g[NMAX + 1];              // cantitatile de bomboane&lt;br /&gt;
int a[GMAX + 1];&lt;br /&gt;
int n, G;                     // nr obiectelor, capacitatea rucsacului&lt;br /&gt;
int main() {&lt;br /&gt;
  cin &amp;gt;&amp;gt; n &amp;gt;&amp;gt; G;&lt;br /&gt;
  for( int i = 1; i &amp;lt;= n; i++ )&lt;br /&gt;
    cin &amp;gt;&amp;gt; g[i];&lt;br /&gt;
&lt;br /&gt;
  for( int i = 1; i &amp;lt;= G; i++ )&lt;br /&gt;
    a[i] = NMAX + 1;&lt;br /&gt;
&lt;br /&gt;
  for( int i = 1; i &amp;lt;= n; i++ )&lt;br /&gt;
    for( int j = G; j &amp;gt;= g[i]; j-- ) {&lt;br /&gt;
      if( a[j] &amp;gt; a[j - g[i]] + 1 )&lt;br /&gt;
        a[j] = a[j - g[i]] + 1;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  if( a[G] == NMAX + 1 )&lt;br /&gt;
    cout &amp;lt;&amp;lt; &amp;quot;NU&amp;quot;;&lt;br /&gt;
  else&lt;br /&gt;
    cout &amp;lt;&amp;lt; a[G];&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Tema =&lt;br /&gt;
Varena&lt;br /&gt;
* [http://varena.ro/problema/rucsac  rucsac]&lt;br /&gt;
*[https://www.varena.ro/problema/ESO ESO] Super Problema !&lt;br /&gt;
Infoarena&lt;br /&gt;
*[https://www.infoarena.ro/problema/Triunghi Triunghi]&lt;br /&gt;
*[https://www.infoarena.ro/problema/Energii Energii]&lt;br /&gt;
*[https://www.infoarena.ro/problema/Lapte Lapte]&lt;br /&gt;
*[https://www.infoarena.ro/problema/Calatorie interplanetara Calatorie interplanetara]&lt;br /&gt;
*[https://www.infoarena.ro/problema/Jocul Jocul]&lt;br /&gt;
*[https://www.infoarena.ro/problema/Ghiozdan Ghiozdan]&lt;br /&gt;
*[https://www.infoarena.ro/problema/Intensitate Intensitate]&lt;/div&gt;</summary>
		<author><name>Bella</name></author>
	</entry>
</feed>