Cod sursa(job #3251443)

Utilizator rotti321Rotar Mircea rotti321 Data 26 octombrie 2024 06:19:34
Problema Parantezare optima de matrici Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 2.29 kb
#include <bits/stdc++.h>
using namespace std;

// INF este valoarea maximă - "infinitul" nostru
const auto INF = std::numeric_limits<unsigned long long>::max();

// T = O(n ^ 3)
// S = O(n ^ 2) - stocăm n x n întregi în tabloul dp

 unsigned long long solve_podm(int n, const vector<int> &d) {
    // dp[i][j] = numărul MINIM înmulțiri scalare cu codare, poate fi calculat produsul
    //            matriceal M_i * M_i+1 * ... * M_j
    vector<vector<unsigned long long>>  dp(n + 1, vector<unsigned long long> (n + 1, INF));

    // Cazul de bază 1: nu am ce înmulți
    for (int i = 1; i <= n; ++i) {
        dp[i][i] = 0ULL;  // 0 pe unsigned long long (voi folosi mai încolo și 1ULL)
    }

    // Cazul de bază 2: matrice d[i - 1] x d[i] înmulțită cu matrice d[i] x d[i + 1]
    // (matrice pe poziții consecutive)
    for (int i = 1; i < n; ++i) {
        dp[i][i + 1] =  1ULL * d[i - 1] * d[i] * d[i + 1];
      //  cout<<dp[i][i+1]<<" ";
    }

    // Cazul general:
    // dp[i][j] = min(dp[i][k] + dp[k + 1][j] + d[i - 1] * d[k] * d[j]), k = i : j - 1
    for (int len = 2; len <= n; ++len) {            // fixăm lungimea intervalului (2, 3, 4, ...)
        for (int i = 1; i + len - 1 <= n; ++i) {    // fixăm capătul din stânga: i
            int j = i + len - 1;                    // capătul din dreapta se deduce: j

            // Iterăm prin indicii dintre capete, spărgând șirul de înmulțiri in două (paranteze).
         //   dp[i][j]=1LL<<60;
            for (int k = i; k < j; ++k) {
                // M_i * ... M_j  = (M_i * .. * M_k) * (M_k+1 *... * M_j)
                unsigned long long new_sol = dp[i][k] + dp[k + 1][j] + 1ULL * d[i - 1] * d[k] * d[j];

                // actualizăm soluția dacă este mai bună
                dp[i][j] = min(dp[i][j], new_sol);
            }
        }
    }

    // Rezultatul se află în dp[1][n]: Numărul MINIM de inmultiri scalare
    // pe care trebuie să le facem pentru a obține produsul M_1 * ... * M_n
    return dp[1][n];

}

int main(){
    ifstream cin("podm.in");
    ofstream cout("podm.out");
    int n,x;
    vector<int> d;
    cin>>n;
    //d.push_back(0);
    for(int i=0;i<=n+1;i++){
        cin>>x;
        d.push_back(x);
    }
    cout<<solve_podm(n,d);
}