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 \(r_{uv}\) od čvora \(u\) do čvora \(v\) (najveća razlika visina na najboljem putu od \(u\) do \(v\)) i rastojanje \(r_{vw}\) od čvora \(v\) do njemu susednog čvora \(w\) (razlika visina), tada je najmanje rastojanje od čvora \(u\) do čvora \(v\) jednako \(\max(r_{uv}, r_{vw})\). Tada se vrednost rastojanja ažurira na osnovu dodele \(r_{uw} := \min(r_{uw}, \max(r_{uv}, r_{vw}))\).
“Težina” grane \((u, v)\) je u ovom primeru definisana kao razlika visina dva čvora koje ta grana spaja. “Dužina” puta \((v_0, v_1, \ldots, v_k)\) 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.
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
int>> rastojanje(m, vector<int>(n, INF));
vector<vector<// podatak da li je do čvora određeno rastojanje pamtimo u matrici
bool>> resen(m, vector<bool>(n, false));
vector<vector<// 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)
int, int, int>,
priority_queue<tuple<int, int, int>>,
vector<tuple<int, int, int>>> pq;
greater<tuple<// rastojanje do početnog čvora je 0
0][0] = 0;
rastojanje[
// krećemo od početnog čvora
0, 0, 0);
pq.emplace(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)
true;
resen[v][k] =
// 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];
}
#include <iostream>
#include <vector>
#include <limits>
#include <queue>
#include <tuple>
using namespace std;
const int INF = numeric_limits<int>::max();
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
int>> rastojanje(m, vector<int>(n, INF));
vector<vector<// podatak da li je do čvora određeno rastojanje pamtimo u matrici
bool>> resen(m, vector<bool>(n, false));
vector<vector<// 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)
int, int, int>,
priority_queue<tuple<int, int, int>>,
vector<tuple<int, int, int>>> pq;
greater<tuple<// rastojanje do početnog čvora je 0
0][0] = 0;
rastojanje[
// krećemo od početnog čvora
0, 0, 0);
pq.emplace(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)
true;
resen[v][k] =
// 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];
}
int main() {
false);
ios_base::sync_with_stdio(int m, n;
cin >> m >> n;int>> visine(m);
vector<vector<for (int i = 0; i < m; i++) {
visine[i].resize(n);for (int j = 0; j < n; j++)
cin >> visine[i][j];
}
cout << najmanjeNapornaStaza(visine) << endl;return 0;
}