Note de curs, clasele 9-10, 22 februarie 2013

From Algopedia
Jump to navigationJump to search

Tema

Discuții rezolvări la teme:

  • megascoala: Floyd-Warshall O(n3) + toate combinațiile O(n3).
  • traseu1: Dijkstra modificat, în loc de sumă calculăm maximul O(n2).
  • grafxy: Dijkstra modificat, pornirea este din mai multe noduri o dată. E necesară implementarea O((M+N) log N) și reprezentarea cu liste de adiacență.

Lecție

Backtracking

  • Algoritmul general, implementări recursive versus nerecursive, ideea că orice program recursiv poate fi scris nerecursiv folosind o stivă.
  • Optimizări de backtracking: pe cît posibil alegerea următoarei opțiuni în O(1). Exemplu la problema damelor, folosirea vectorilor de linii, coloane și diagonale.
  • Euristici:
    • un backtracking informat va fi mai eficient decît unul neinformat; optimizările sînt dependente de problemă; există unele idei generale.
    • alegerea locului cu număr minim de posibilități (early pruning); exemple:
      • problema calului, selecția în ordinea inversă a numărului posibil de mutări
    • alegerea greedy (drum hamiltonian)
    • funcție de verificare dacă soluția parțială mai are șanse să ducă la o soluție
      • se obține prin relaxarea unora din condiții
      • drum hamiltonian: soluția parțială să fie mai mică decît cel mai bun drum găsit pînă acum
      • drum hamiltonian: dacă soluția parțială plus numărul de arce rămase ori costul minim al unui arc este mai mare ca soluția optimă găsită pînă acum, ne putem opri
  • Omorîrea backtrackingului. Tehnică folositoare și atunci cînd vreți să măsurați cît timp ruleaza programul vostru:
#include <sys/time.h>

#define MAX_VAL 990

int startT;
int stop;

void bkt(...) {
  struct timeval tv;

  if ( stop )
    return;
  gettimeofday(&tv, NULL);
  if (  tv.tv_sec * 1000 + tv.tv_usec / 1000 - startT > MIN_VAL ) {
    stop = 1;
    return;
  }
  for(...) // generare mutari urmatoare
}

int main() {
  struct timeval tv;

  gettimeofday(&tv, NULL);
  startT = tv.tv_sec * 1000 + tv.tv_usec / 1000; // pastram milisecunde
  stop = 0;
...
  return 0;
}

Operațiuni pe biți

  • Operatorii pe biți: &, |, ~, ^, <<, >>. Atenție: shift este mult mai rapid decît împărțirea! Vezi tabelul din lecția 14, clasele VI/VII/VIII.
  • Extragerea unui bit. Ideea de mască. Constante hexa în C (care încep cu 0x, ex: 0xFF12).
  • Setarea unui bit pe 0.
  • Setarea unui bit pe 1.
  • Compunerea mai multor valori într-un întreg. Aplicație: reprezentarea zecimal împachetat.
  • Aplicație: operații pe mulțimi mari, reuniune, intersecție, etc. De menționat că reuniunea și intersecția se fac mai rapid, deoarece reunim cîte 32 (sau 64) elemente deodată.
  • Codul Gray

Teme

La alegere, pentru viitor:

  • implementați un backtracking cu euristică și omorît, ca să vă faceți mîna, cum ar fi drumul hamiltonian într-un graf (în particular această problemă are o soluție exponențială mai rapidă decît backtracking-ul, prin programare dinamică).
  • operațiuni pe vector de biți:
    • int get(int i, unsigned int v[]) returnează valoarea bitului pe poziția i.
    • void set(int i, unsigned int v[], int e) setează elementul pe poziția i la valoarea e, unde e este 0 sau 1.
  • se dă o permutare, a cîta este în ordine lexicografică?
  • se dă un număr între 0 și n!-1, ce permutare reprezintă el în ordine lexicografică?
  • implementați permutările sub forma unei funcții care la fiecare apel ne returnează încă o permutare (foarte util în anumite situații). Aplicație directă a problemei anterioare.
  • ultimele trei probleme, dar pentru combinări.