Pagini recente » Cod sursa (job #3291508) | Cod sursa (job #3285848) | Cod sursa (job #3292824) | Cod sursa (job #3285238) | Cod sursa (job #3292646)
#include <iostream>
#include <limits>
#include <vector>
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];
}
// 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).
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() {
int n;
cin >> n;
vector<int> d(n + 1);
for (int i = 0; i < n + 1; ++i) {
cin >> d[i];
}
cout << solve_podm(n, d) << endl;
return 0;
}