Cod sursa(job #3176770)

Utilizator pomeneacristianandreiPomenea Cristian-Andrei pomeneacristianandrei Data 27 noiembrie 2023 18:59:13
Problema Ghiozdan Scor 0
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 3.44 kb
#include <iostream>
#include <fstream>

using namespace std;

/** O modificare a rucsacului standard, care doreste:
    ---> Cat mai bine umplut, cu cat mai putin spatiu liber. NU ne intereseaza maximizarea valorii
    ---> Sa fie cat mai putine obiecte
    ---> Obiectele folosite TREBUIESC afisate

    Deoarece n, nr de obiecte, este 2 * 1e4 si R e 75 * 1e3 iar obiectele au greutatile intre 1 si 200, vom putea face dinamica dupa greutatile posibile.
    Putem folosi frecventa si problema devine asemanatoare cu rucsacul 1D, cu obiecte cu frecvente diferite. Insa, cea standard, NU cere nr minim
    de obiecte si NU cere tiparirea solutiei.
**/

ifstream f( "ghiozdan.in" );
ofstream g( "ghiozdan.out" );

const int dim_capacit = 75005, dim_obiecte = 20002;

int n, greut[ dim_obiecte ], frecv[ 202 ], R;
int dp[ dim_capacit ]; /// dinamica ce se efectueaza pentru fiecare capacitate admisibila a Rucsacului
int tata[ dim_capacit ]; /// tata[ x ] = y <=> starea actuala, x, este obtinuta din starea y, la cares-a adaugat un numar d eobiecte de acelasi tip.



int main()
{
    int i, j, tinta, capacit;

    f >> n >> R;
    for( i = 1; i <= n; ++i )
        f >> greut[ i ],
        ++frecv[ greut[i] ];

    dp[ 0 ] = 1; /// Ca sa nu imi strice calculele. La final scad 1. Intotdeauna obiectul de greutate 0 poate fi luat :)
    for( i = 200; i > 0; --i ) /// i = greutatea obiectului actual. Este esential sa caut descrescator, sa folosesc cat mai putine obiecte
        if(frecv[ i ]  !=  0 ) /// Daca exista vreun obiect de greutate i
            for( capacit = R; capacit >= 0; --capacit )
                if( dp[ capacit ]  !=  0 )
                    {
                        /// Verific cate obiecte pot fi bagate in spatiul ramas. Nr lor NU poate depasi frecventa disponibila
                        tinta = min( frecv[ i ], (R - capacit) / i );
                        for (j = 1; j <= tinta; ++j) /// Pun un obiect, doua obiecte, ... pana cand ating frecventa disponibila sau dau peste o capacitate deja rezolvata
                            {
                                if ( dp[j * i + capacit]  !=  0 )
                                    break;

                                /// Fac pasul de dinamica in fata, precum la problema cu broastele
                                dp[ j * i + capacit ] = dp[ capacit ] + j; /// Nr de obiecte pe care il folosesc pentru noua capacitate se obtine adaugand noul nr al obiectelor folosite la vechea capacitate
                                tata[ j * i + capacit ] = i;
                            }
                    }


    //cout << endl << "Am terminat rucsacul. Apasa Enter." << endl;
    //cin.get();
    for( i = 1; i <= R; ++i )
        if( dp[ i ]  >  1 )
            g << "Numarul minim de obiecte pentru greutatea  " << i << "  este: " << dp[ i ] - 1 << endl;
        else
            g << "Greutatea " << i << " NU poate fi formata cu niciun obiect." << endl;
    /// Gasesc cea mai mare capacitate a rucsacului, <= R
    i = R;
    while( dp[ i ]  == 0 )
        --i;
    /// Capacitatea maxima pana la care poate fi incarcat rucsacul si afisez langa ea, numarul de obiecte
    g << i << " "  << dp[ i ] - 1 << endl;
    cout << "Din " << R << " pot umple " << i << " unitati, cu " << dp[ i ] - 1 << " obiecte. Apasa Enter." << endl;

    while( --dp[ i ] )
        {
            g << tata[ i ] << endl;
            i = i - tata[ i ];
        }

    return 0;
}