Pagini recente » Cod sursa (job #454285) | Cod sursa (job #249650) | Cod sursa (job #2207680) | Cod sursa (job #882364) | Cod sursa (job #3346685)
/*
A1 A2 A3 .... A5
*/
#include <limits>
#include <vector>
#include <fstream>
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() {
ifstream fin("podm.in");
ofstream fout("podm.out");
int n;
fin >> n;
vector<int> d(n + 1);
for (int i = 0; i <= n; i++) {
fin >> d[i];
}
fout << solve_podm(n, d);
}