Cod sursa(job #3184451)

Utilizator Andrei_EmanuelPuiu Andrei Stefan Emanuel Andrei_Emanuel Data 16 decembrie 2023 00:13:58
Problema Parantezare optima de matrici Scor 70
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 4.81 kb
#include <iostream>
#include <fstream>
using namespace std;

const int dim = 505;
const int INF = 1e9;

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

int dimens[ dim ]; ///matricea 1 are dimeniunile (dimens[1], dimens[2]). Ea se inmulteste cu matricea 2, cu dimensiunile (dimens[2], dimens[3]), ...
int dp[ dim ][ dim ], n;


/**
    Matricea va avea pe diagonala principala 0, pe paralela la diag pp va avea prod care reprezinta nr de operatii necesar inm a doua matrici consec
    Pe urmatoarea paralela la diag pp, nr minim de operatii necesar pt produsul inm a 3 matrici consec...
    Daca am sirul de matrici A1 * A2 * A3
    0 x y
      0 z
        0
    x = dimens(A1) * dimens(A2), adica cel mai mic nr de inm pt A1 * A2
    z = dimens(A2) * dimens(A3), adica cel mai mic nr de inm pt A2 * A3
    y = cel mai mic nr de inm intre (A1 * A2) * A3  si  A1 * (A2 * A3)

    dp[ i ][ j ] = cel mai mic nr de inmultiri pentru segmentul de matrici A_i, A_(i + 1), A_(i + 2), ..., A_j. Adica, in momentul in care fac o rupere la poz k,
    am doua subsiruri, A_i, ... A_(k - 1) si A_k, ... A_j, al caror numar optim este deja calculat, uitandu-ma pe linie, in stanga, si pe coloana, in jos.


    3
    2 3 4 1


    dim A = (2, 3)
    dim B = (3, 4)
    dim C = (4, 1)
    (A * B)  => 24 inmultiri => dimens (2, 4)
    (B * C)  => 12 inmultiri => dimens (3, 1)

    (A * B) * C <=> (2, 4) * (4, 1) => (2, 1) => 24 + 8 inmultiri (24 + 2*4*1)
    A * (B * C) <=> (2, 3) * (3, 1) => (2, 1) => 6 + 12 inmultiri (2*3*1 + 12)
**/


void afiseaza_dim()
{
    int i, j;
    g << "Sirul de dimensiuni:" << endl;
    for( i = 1; i <= n; ++i )
        g << "(" << dimens[ i ] << ", " << dimens[ i + 1 ] << ")  ";
    g << endl << endl;

}

void afiseaza_prod_fracturare( int st, int dr, int x )
{
    if( st <= x && x <= dr )
        {
            g << "      Fracturez la indicele " << x << ", adica obtin intervalele de indici [" << st<< ", " << x << "], [" << x + 1 << ", " << dr << "]" << endl;
            g << "      Matricea rezultat, obtinuta prin prod matricilor dintre indicii [" << st << ", " << x << "] are dimensiunea (" << dimens[ st ] << ", " << dimens[ x + 1 ] << ")" << endl;
            g << "      Matricea rezultat, obtinuta prin prod matricilor dintre indicii [" << x + 1 << ", " << dr << "] are dimensiunea (" << dimens[ x + 1 ] << ", " << dimens[ dr + 1 ] << ")" << endl;
            g << "      Produsul de fracturare: " << dimens[ st ] * dimens[ x + 1 ] * dimens[ dr + 1 ] << endl;
            g << endl << endl;
        }
}

void afiseaza_dp()
{
    int i, j;
    for( i = 1; i <= n; ++i )
        {
            for( j = 1; j <= n; ++j )
                if( dp[ i ][ j ]  <  INF )
                    g << dp[ i ][ j ] << "  ";
                else
                    g << "*  ";
            g << endl;
        }
    g << endl << endl;
}


int main()
{
    int i, j, k, termen, prod3;

    f >> n;
    for( i = 1; i <= n + 1; ++i )
        f >> dimens[ i ];

    // afiseaza_dim();

    for( i = 1; i < n; ++i )
        dp[ i ][ i + 1 ] = dimens[ i ]  *  dimens[ i + 1 ]  *  dimens[ i + 2 ]; /// Se inm matr A_i cu matr A_(i+1) si se face un nr de inm egal cu acel prod

    // afiseaza_dp();



    /// Incep sa construiesc piramida incepand cu a doua para la DP
    for( i = n - 2; i >= 1; --i )
        for( j = i + 2; j <= n; ++j ) /// dp[i][i+1] sunt deja calculate
            {
                // g << "Calculez dp[" << i << "][" << j << "]" << endl;
                dp[ i ][ j ] = INF;


                for( k = i; k < j; ++k )   /// k este indicele la care facturez
                    {
                        prod3 = dimens[ i ] * dimens[ k + 1 ] * dimens[ j + 1 ];   /// Produsul intre ultimele doua matrici (dupa comprimarile necesare si anterioare)
                        // afiseaza_prod_fracturare(i, j, k);
                        // g << "      Minimul intre cat era inainte si ( dp[" << i << "][" << k << "]  +  dp[" << k + 1 << "][" << j << "])" << " + produsul pentru fracturare";
                        // g << ", adica intre " << dp[ i ][ j ] << " si (" << dp[ i ][ k ] +  dp[ k + 1 ][ j ] << ") + " << prod3 << endl;

                        termen = dp[ i ][ k ] +  dp[ k + 1][ j ] + prod3;   /// Inmultirea matricilor finale + inmultirea apsilor anteriori la parantezele puse
                        // g << "      produsul de 3, termen = " << termen << endl;
                        dp[ i ][ j ] = min( dp[ i ][ j ], termen );   /// Retin doar minimul

                        // g << endl << "  -->  dp[" << i << "][" << j << "] = " << dp[ i ][ j ] << endl << endl;
                    }

                // g << endl;
                // afiseaza_dp();
            }


    g << dp[ 1 ][ n ];   /// Afisez doar varful piramidei
    return 0;
}