#include #include typedef unsigned long long ull; // 64-bitový typ #define MAXRS 1000 // Maximální rozměr #define MAXP (MAXRS*MAXRS+1) // Maximální počet políček #define MAXH 1000000 // Maximální výška #define INFTY (1ULL<<62) // Pro naše účely nekonečno int R, S; // Parametry vstupu ull cS, cM, cT; int h[MAXRS][MAXRS]; // Vstup int hint[MAXRS][MAXRS][4]; // Předpočítané mosty/tunely pro směr // vlevo, vpravo, nahoru, dolů // Přepočet mezi souřadnicemi a pořadovým číslem políčka #define E(i,j) ((i)*MAXRS + (j)) #define D(i,j,c) i = (c)/MAXRS, j = (c)%MAXRS ull best[MAXP]; // Nejlepší zatím známé ohodnocení políčka int prev[MAXP]; // Předchůdce na nejkratší cestě /** Halda pro Dijkstrův algoritmus **/ int heap[MAXP]; // Halda sama (obsahuje čísla políček) int hcnt; // Počet políček v haldě int back[MAXP]; // Pro každé políčko pozice v haldě // (0=není tam) // Prohození dvou prvků v haldě static inline void swap(int i, int j) { int z = heap[i]; heap[i] = heap[j]; heap[j] = z; back[heap[i]] = i; back[heap[j]] = j; } // Úprava (nastavení či snížení) ohodnocení políčka static void heap_set(int i, ull new) { best[i] = new; if (back[i]) // Už je v haldě? i = back[i]; else // Ne, musíme ho přidat { heap[++hcnt] = i; back[i] = hcnt; i = hcnt; } while (i > 1 && best[heap[i/2]] > best[heap[i]]) { // Vybubláme nahoru swap(i, i/2); i /= 2; } } // Nalezení a smazání minima z haldy static int heap_delmin(void) { if (!hcnt) return -1; int old = heap[1]; swap(1, hcnt); hcnt--; int i = 1; // Zabubláme dolů while (2*i <= hcnt) { int j = 2*i; if (j+1 <= hcnt && best[heap[j+1]] < best[heap[j]]) j++; if (best[heap[i]] < best[heap[j]]) break; swap(i, j); i = j; } back[old] = 0; return old; } /** Předvýpočet mostů a tunelů **/ // Pomocný zásobník struct pt { int i, j, h; }; static struct pt stack[MAXRS+1]; static void precalc2(int d, int i0, int j0, int ri, int rj, int si, int sj) { /* * Předpočítá hint[*][*][d]. * Vyrazí z počátečního políčka (i0,j0), * (ri,rj) je "řádkový" směr, (si,sj) "sloupcový" směr. */ while (i0 >= 0 && i0 < R && j0 >= 0 && j0 < S) { for (int s=-1; s<=1; s+=2) // 1=tunely, -1=mosty { int i=i0, j=j0; int sp = 0; stack[0] = (struct pt) { 0, 0, MAXH+1 }; // Zarážka while (i >= 0 && i < R && j >= 0 && j < S) { int ht = s*h[i][j]; while (ht > stack[sp].h) sp--; if (ht == stack[sp].h) { int dist = abs(stack[sp].i - i) + abs(stack[sp].j - j); if (dist > 1) hint[i][j][d] = dist; sp--; } stack[++sp] = (struct pt) { i, j, ht }; i += si, j += sj; } } i0 += ri, j0 += rj; } } static void precalc(void) { precalc2(0, 0, 0, 1, 0, 0, 1); precalc2(1, 0, S-1, 1, 0, 0, -1); precalc2(2, 0, 0, 0, 1, 1, 0); precalc2(3, R-1, 0, 0, 1, -1, 0); } // Obsloužení hrany z políčka x do (i,j) s cenou cost static void try(int x, int i, int j, ull cost) { // Nevede do autu? if (i < 0 || i >= R || j < 0 || j >= S) return; // Má povolený rozdíl výšek? int ii, jj; D(ii, jj, x); if (h[ii][jj] > h[i][j]+1 || h[ii][jj] < h[i][j]-1) return; // Dává lepší ohodnocení než to stávající? cost += best[x]; int y = E(i,j); if (cost < best[y]) { heap_set(y, cost); prev[y] = x; } } int main(void) { // Čtení vstupu scanf("%d%d%lld%lld%lld", &R, &S, &cS, &cM, &cT); for (int i=0; i= 0) { int i, j; D(i, j, x); // Posun na sousední políčko try(x, i, j-1, cS); try(x, i, j+1, cS); try(x, i-1, j, cS); try(x, i+1, j, cS); // Stavíme tunel nebo most if (hint[i][j][0]) // Doleva try(x, i, j - hint[i][j][0], ((h[i][j-1] < h[i][j]) ? cM : cT) * (hint[i][j][0]-1) + cS); if (hint[i][j][1]) // Doprava try(x, i, j + hint[i][j][1], ((h[i][j+1] < h[i][j]) ? cM : cT) * (hint[i][j][1]-1) + cS); if (hint[i][j][2]) // Nahoru try(x, i - hint[i][j][2], j, ((h[i-1][j] < h[i][j]) ? cM : cT) * (hint[i][j][2]-1) + cS); if (hint[i][j][3]) // Dolů try(x, i + hint[i][j][3], j, ((h[i+1][j] < h[i][j]) ? cM : cT) * (hint[i][j][3]-1) + cS); } // Výpis cesty if (best[E(0,0)] < INFTY) { printf("%lld\n", best[E(0,0)]); int pos = 0; do { int i, j; D(i, j, pos); printf("%d %d\n", i, j); pos = prev[pos]; } while (pos != E(R-1,S-1)); printf("%d %d\n", R-1, S-1); } else puts("NEEXISTUJE"); return 0; }