resources/2018_Territoriali_soluzioni.md
... ...
@@ -150,19 +150,36 @@ Questa soluzione dovrebbe essere molto più veloce ed è probabilmente sufficien
150 150
151 151
#### Soluzione ottima
152 152
153
-La soluzione ottimale a questo problema consiste nell'usare una variazione dell'[Algoritmo di Dijkstra](https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm).
153
+La soluzione ottimale a questo problema consiste nell'usare una variante del noto [Algoritmo di Dijkstra](https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm). Anziché sommare il peso degli archi che si attraversano, per questo problema si può considerare il massimo tra il peso del nuovo arco e il massimo peso degli archi percorsi fino a quel momento. Il concetto di "distanza" diventa quindi il peso massimo tra quelli degli archi attraversati per arrivare fino lì, nel cammino migliore (ovvero quello a "distanza" minore, che equivale al peso massimo minore).
154
+
155
+Nell'implementazione che segue il grafo viene memorizzato ed esplorato in forma implicita (senza la costruzione di liste o matrici di adiacenza), sfruttando il fatto che - a meno dei bordi - ogni punto $(x,y)$ della mappa ha come nodi vicini i punti $(x-1,y)$, $(x+1,y)$, $(x,y-1)$ e $(x,y+1)$. Il peso degli archi può essere calcolato all'occorrenza come valore assoluto della differenza delle altezze tra i due punti.
156
+
154 157
155 158
```c++
159
+#include <cstring>
160
+#include <iostream>
161
+#include <queue>
156 162
#define INFTY 1000000000
157 163
164
+using namespace std;
165
+
158 166
const int MAXH = 100;
159 167
const int MAXW = 100;
160 168
161
-int A[MAXH + 2][MAXW + 2];
162
-int D[MAXH + 2][MAXW + 2];
169
+int A[MAXH + 2][MAXW + 2]; // Matrice delle altezze
170
+int D[MAXH + 2][MAXW + 2]; // Matrice della "distanza" dal nodo di partenza
163 171
int H, W;
164 172
165 173
int compute() {
174
+ // Algoritmo di Dijkstra.
175
+
176
+ // Gli elementi nella coda di priorità sono della forma (d, (x, y))
177
+ // dove d indica la distanza per raggiungere il nodo (x,y).
178
+ // priority_queue mette per primi i nodi con d maggiore. Poiché invece
179
+ // vogliamo estrarre per primi i nodi a distanza d minore, inseriremo
180
+ // le distanze con segno negato, per "ribaltare" l'ordinamento.
181
+ // Dopo l'estrazione, è sufficiente negare di nuovo il valore per riottenere
182
+ // la distanza positiva originale.
166 183
priority_queue<pair<int, pair<int, int>>> q;
167 184
168 185
q.push(make_pair(0, make_pair(1, 1)));
... ...
@@ -171,14 +188,21 @@ int compute() {
171 188
auto top = q.top();
172 189
q.pop();
173 190
191
+ // Se il nodo è già stato esplorato e la sua miglior distanza è stata calcolata,
192
+ // non proseguo.
174 193
if (D[top.second.first][top.second.second] != INFTY)
175 194
continue;
176 195
196
+ // Memorizziamo la miglior "distanza" con cui è possibile raggiungere questo nodo.
177 197
D[top.second.first][top.second.second] = -top.first;
178 198
199
+ // Esploriamo i quattro vicini.
179 200
for (int i = -1; i <= 1; i++) {
180 201
for (int j = -1; j <= 1; j++) {
181 202
if (i * j == 0) {
203
+ // La miglior distanza con cui si può raggiungere il nuovo nodo è il massimo tra:
204
+ // - la distanza con cui si può raggiungere il nodo attuale
205
+ // - il peso del nuovo arco
182 206
q.push(make_pair(
183 207
-max(-top.first,
184 208
abs(A[top.second.first][top.second.second] -