Cuburi3

Vom prezenta trei soluţii, toate aplicând metoda programării dinamice, prima fiind una cu memoizare, a doua una clasică iar a treia folosind arbori indexaţi binar.

Varianta 1

Vom arăta că soluţia are structură optimă: presupunem că turnul de cuburi format din cuburile numerotate cu p1, p2, ..., pk în această ordine are înălţime maximă. Acum turnul de cuburi format din cuburile p2, ..., pk este cel mai înalt turn care îl are la bază pe p2. Dacă ar exista turn mai înalt care la bază să îl aibă tot pe p2, atunci acesta s-ar putea aşeza pe p1 şi astfel am obţine un turn mai înalt decât cel din presupunerea iniţială. Am afirmat că acel ipotetic turn mai înalt care începe cu p2 l-am aşeza pe p1, deoarece p1 nu poate să apară în acest turn care începe cu p2, ţinând cont de proprietăţile turnului.

Descompunem problema în subprobleme: pentru orice i (1 ≤ i ≤ n) trebuie să determinăm înălţimea maximă a turnului care la bază îl are pe cubul i. Fie bsti turnul de înălţime maximă ce se termină pe poziţia i.

  • bsti = max { bstj : 1 ≤ j ≤ n, i != j şi gj ≤ gi şi lj ≤ li } + li

Vom determina soluţia optimă recursiv şi vom păstra rezultatele subproblemelor, de unde le vom citi dacă în continuare va fi nevoie de ele. Şirul care memorează rezultatele subproblemelor se iniţializează cu 0, pentru a şti dacă elementul respectiv s-a calculat deja sau nu.

Algoritmul lucrează în O(n2), şi are nevoie de Θ(n) memorie.

Varianta 2

O altă soluţie având complexitatea O(n2) se poate obţine sortând cuburile descrescător după lungimea laturii şi în caz de egalitate după greutate. După sortare putem aplica metoda programării dinamice în felul următor:

  • bsti – înălţimea celui mai înalt turn ce se poate construi în aşa fel încât ultimul cub să fie cubul i.

Sortarea ne garantează că cubul i se poate aşeza doar pe cuburi având indice mai mic. Astfel recurenţa va fi:

  • bsti = max { bstj : 1 ≤ j < i şi gj ≥ gi} + li

Soluţia se va afla în elementul maxim din bst. Pentru a putea reconstrui soluţia, trebuie reţinut pentru fiecare i, acel j prin care s-a obţinut maximul pentru bsti.

Varianta 3

Folosind arbori indexaţi binar (notat în continuare cu AIB), vom obţine un algoritm de complexitate O(n log n) care necesită Θ(n) memorie. Deoarece cerinţa problemei este de a construi un subşir (g1, l1), (g2, l2), ..., (gk, lk) astfel încât g1 ≥ g2 ≥ ... ≥ gk şi l1 ≥ l2 ≥ ... ≥ lk, întâi sortăm descrescător cuburile în funcţie de lungimea laturii, iar în caz de egalitate, descrescător în funcţie de greutate.

Pentru poziţia i vom alege bstj maxim, astfel încât greutatea cubului j, j < i, să fie mai mare sau egală cu greutatea cubului i. Observăm că j < i este echivalent cu lj ≥ li, adică condiţia lungimilor laturilor este îndeplinită. Însă, noi avem nevoie doar de greutăţile mai mari sau egale decât greutatea curentă gi. Aici intervine AIB, în felul următor:

  • sortăm crescător greutăţile cuburilor, eliminăm duplicatele obţinând un vector de lungime lung;
  • căutăm în acest vector cu algoritmul căutării binare greutatea curentă gi, găsind-o pe o poziţie p;
  • interogăm AIB-ul pe intervalul [p, lung] pentru a determina max { bstj : 1 ≤ j < i şi gj ≥ gi};
  • actualizăm în AIB intervalul [1, p] cu bsti.

Operaţiile de interogare şi actualizare într-un AIB au complexitatea O(log(n)).