Processing math: 100%

Najmanje naporna staza - Rešenje

Postavka

Dajkstrin algoritam

Zadatak se može rešiti jednostavnom modifikacijom Dajkstrinog algoritma za pronalaženje najkraćeg puta od gornjeg levog polja, pa do svih ostalih polja, uključujući i poslednje, donje desno polje. Jedina razlika u odnosu na uobičajeni Dajkstrin algoritam se u slučaju da je poznato najmajnje rastojanje ruv od čvora u do čvora v (najveća razlika visina na najboljem putu od u do v) i rastojanje rvw od čvora v do njemu susednog čvora w (razlika visina), tada je najmanje rastojanje od čvora u do čvora v jednako max(ruv,rvw). Tada se vrednost rastojanja ažurira na osnovu dodele ruw:=min(ruw,max(ruv,rvw)).

“Težina” grane (u,v) je u ovom primeru definisana kao razlika visina dva čvora koje ta grana spaja. “Dužina” puta (v0,v1,,vk) je ovde definisana kao maksimalna razlika visina čvorova na putu. “Zbir” dužine dva puta jednak je njihovom maksimumu. Ova metrika zadovoljava sledeća svojstva:

Može se dokazati da su ova svojstva dovoljna da osiguraju korektnost Dajkstrinog algoritma.

Prikaži kompletan kôd

int najmanjeNapornaStaza(const vector<vector<int>>& visine) {
  // dimenzije matrice
  int m = visine.size(), n = visine[0].size();
  // rastojanje od početnog do svakog drugog čvora pamtimo u matrici 
  vector<vector<int>> rastojanje(m, vector<int>(n, INF));
  // podatak da li je do čvora određeno rastojanje pamtimo u matrici
  vector<vector<bool>> resen(m, vector<bool>(n, false));
  // red sa prioritetom koji koji sadrži trojke na čijem je prvom mestu
  // dužina grane, a zatim čvor iz kog ta grana polazi
  // (njegove koordinate)
  priority_queue<tuple<int, int, int>,
                 vector<tuple<int, int, int>>,
                 greater<tuple<int, int, int>>> pq;
  // rastojanje do početnog čvora je 0
  rastojanje[0][0] = 0;

  // krećemo od početnog čvora
  pq.emplace(0, 0, 0);
  while (!pq.empty()) {
    // skidamo element sa vrha reda sa prioritetom
    auto [tezina, v, k] = pq.top();
    pq.pop();
    // ako je do čvora na poziciji (v, k) ranije određen najkraći put,
    // taj čvor preskačemo
    if (resen[v][k])
      continue;
    // pamtimo da smo upravo odredili najkraći put do čvora na
    // poziciji (v, k)
    resen[v][k] = true;

    // prolazimo kroz sve susede ovog čvora
    int dv[] = {-1, 1, 0, 0};
    int dk[] = {0, 0, -1, 1};
    for (int i = 0; i < 4; i++) {
      int vv = v + dv[i];
      int kk = k + dk[i];
      if (!(0 <= vv && vv < m && 0 <= kk && kk < n))
        continue;

      // do kojih je najkraće rastonja još nepoznato
      if (resen[vv][kk])
        continue;

      // težina grane od trenutnog do susednog čvora
      int razlika = abs(visine[vv][kk] - visine[v][k]);
      // ažuriramo rastojanje do suseda ako je manje od dosadašnjeg
      int novoRastojanje = max(rastojanje[v][k], razlika);
      if (novoRastojanje < rastojanje[vv][kk]) {
        rastojanje[vv][kk] = novoRastojanje;
        pq.emplace(rastojanje[vv][kk], vv, kk);
      }
    }
  }
  // vraćamo najkraće rastojanje do ciljnog polja
  return rastojanje[m-1][n-1];
}