Cod sursa(job #2421138)

Utilizator BlaugranasEnal Gemaledin Blaugranas Data 14 mai 2019 12:46:25
Problema Parantezare optima de matrici Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 1.92 kb
// http://www.cs.ust.hk/mjg_lib/bibs/DPSu/DPSu.Files/0603055.pdf

#include <fstream>
#include <algorithm>
#include <stack>
#include <map>

using namespace std;

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

const int N_MAX = 500;

int N, nrBridges = -1;
pair<int, int> Bridges[2 * N_MAX], w[N_MAX + 2];
map<pair<int, int>, int> Childs;
long long M[2 * N_MAX][N_MAX + 1];

void Mark_Bridges() {
	rotate(w, min_element(w, w + N), w + N); //aducem cel mai mic numar pe primul loc
	for (int i = 0; i < N; ++i)
		w[i].second = i;
	w[N] = w[0];
	stack<int> S; //stiva in care retinem indici
	for(int i = 1; i <= N; ++i) { //parcurgem in sens invers trigonometric
		S.push(i - 1);
		while (w[i] < w[S.top()]) {
			int t = S.top();
			S.pop();
			Bridges[++nrBridges].first = S.top(), Bridges[nrBridges].second = t;
			Bridges[++nrBridges].first = t, Bridges[nrBridges].second = (i == N ? 0 : i);
			Childs[make_pair(S.top(), (i == N ? 0 : i))] = nrBridges; //este minson, iar nrBridges - 1 este maxson
		}
	}
}

long long Partition() {
	for (int ind = 0; ind <= nrBridges; ++ind) {
		int i = Bridges[ind].first, j = Bridges[ind].second;
		if (w[i] > w[j]) swap(i, j);
		if (!Childs.count(Bridges[ind])) {//frunza
			M[ind][i] = 0;
			for (int k = 0; k < N; ++k) //parcurgem toate conurile formate cu frunza (i, j)
				if (w[k] < w[i])
					M[ind][k] = 1LL * w[i].first * w[j].first * w[k].first;
		}
		else {
			int s = Childs[Bridges[ind]];
			M[ind][i] = M[s][i] + M[s - 1][i];
			for (int k = 0; k < N; ++k) //parcurgem toate conurile formate puntea (i, j)
				if (w[k] < w[i])
					M[ind][k] = min(M[ind][i] + 1LL * w[i].first * w[j].first * w[k].first, M[s][k] + M[s - 1][k]);
		}
	}
	return M[Childs[make_pair(0, 0)]][0] + M[Childs[make_pair(0, 0)] - 1][0];
}

int main() {
	in >> N;
	++N;
	for (int i = 0; i < N; ++i)
		in >> w[i].first;

	Mark_Bridges();
	out << Partition();

	return 0;
}