#include #include #define MAXR 1000 #define MAXS 1000 int R, S; // rozměry městečka int budova[MAXR+2][MAXS+2]; // výška budovy na daném poli int Z[MAXR+2][MAXS+2]; // zádržnost nejpropustnější cesty z okraje //// IMPLEMENTACE HALDY {{{ //// struct pole { int r; int s; }; struct pole halda[MAXR*MAXS+2]; // indexujeme od jedničky int konec_haldy = 1; int halda_Z(int i) { if (i < 0) return INT_MIN; if (i >= konec_haldy) return INT_MAX; return Z[halda[i].r][halda[i].s]; } void halda_prohod(int i, int j) { struct pole tmp = halda[i]; halda[i] = halda[j]; halda[j] = tmp; } void halda_pridej(struct pole p) { int poz = konec_haldy++; halda[poz] = p; while (poz > 1 && halda_Z(poz/2) > halda_Z(poz)) { halda_prohod(poz, poz/2); poz /= 2; } } struct pole halda_vyber(void) { // najdi a odeber minimum struct pole minimum = halda[1]; // prohoď s posledním prvkem halda[1] = halda[--konec_haldy]; // a zmenši haldu int poz = 1; // zabublej nový kořen dolů while (poz*2 < konec_haldy) { int kam; if (halda_Z(poz*2) < halda_Z(poz*2 + 1)) halda_prohod(poz, kam=poz*2); else halda_prohod(poz, kam=poz*2 + 1); poz = kam; } return minimum; } //// KONEC IMPLEMENTACE HALDY }}} //// int max(int a, int b) { return (a > b) ? a : b; } void prohledej_souseda(int mojeZ, int r, int s) { if (Z[r][s] == INT_MAX) { Z[r][s] = max(budova[r][s], mojeZ); halda_pridej((struct pole){r,s}); } // Všimněte si, že jakmile jednou Z nastavíme, už není třeba // ho měnit. To je drobný rozdíl oproti normálnímu Dijkstrovi, // který v řešení nebyl zmíněn. Rozmyslete si. } int main(void) { scanf("%d %d", &R, &S); for (int r = 0; r < R; r++) { for (int s = 0; s < S; s++) { scanf("%d", &budova[r][s]); if (r == 0 || s == 0 || r == R-1 || s == S-1) { // Abychom nemuseli vytvářet virtuální okrajový vrchol "o", na // začátku přidáme do haldy rovnou všechna políčka na okrajích. // Je to jako kdybychom Dikstrův algoritmus spustili až od // druhého kroku. Z[r][s] = budova[r][s]; // z okrajových polí vše odteče halda_pridej((struct pole){r,s}); } else { Z[r][s] = INT_MAX; // "nekonečno" (zatím nevíme, kolik odteče) } } } while (konec_haldy > 1) { struct pole pole = halda_vyber(); int r = pole.r, s = pole.s; int mojeZ = Z[r][s]; fprintf(stderr, "Zavírám (%d, %d), Z=%d\n", r, s, mojeZ); if (r > 0) prohledej_souseda(mojeZ, r-1, s); if (r < R-1) prohledej_souseda(mojeZ, r+1, s); if (s > 0) prohledej_souseda(mojeZ, r, s-1); if (s < S-1) prohledej_souseda(mojeZ, r, s+1); } // Po skončení Dijsktry obsahuje Z výšku haladiny na každém poli (od země). unsigned long long V = 0; for (int r = 0; r < R; r++) { for (int s = 0; s < S; s++) { fprintf(stderr, "(%d, %d), Z=%d, budova=%d, sloupec=%d\n", r, s, Z[r][s], budova[r][s], Z[r][s] - budova[r][s]); V += Z[r][s] - budova[r][s]; } } printf("%llu\n", V); }