#include #include #include //////////////////////////////////////////////////////////////////////////////// /// Datové struktury typedef struct s_hrana t_hrana; struct s_hrana { int kam; int delka; t_hrana *dalsi; }; typedef struct s_mesto t_mesto; struct s_mesto { // Načteno ze vstupu: int interval; int delka; int offset; t_hrana *sousede; // V průběhu výpočtu: int odkud; // index města, přes které vede nejkratší cesta sem int cas; // nejmenší čas, na který se sem umíme dostat int cas_dal; // nejmenší čas, kdy umíme zase pokračovat dál int halda_index; // index v haldě (pro provádění updatů, -1 = není v haldě) }; typedef struct { int mesto; int cas; } t_halda; // Globální data: int N, M, start, cil; // parametry t_mesto *mesto; // pole měst (dynamicky alokované) t_halda *halda; // pole pro haldu (dynamicky alokované) int halda_prvku = 0; //////////////////////////////////////////////////////////////////////////////// /// Halda void halda_swap(int i, int j) { // Prohození v haldě: t_halda temp = halda[i]; halda[i] = halda[j]; halda[j] = temp; // Update odkazů: mesto[halda[i].mesto].halda_index = i; mesto[halda[j].mesto].halda_index = j; } void halda_bublej_nahoru(int i) { int up = (i - 1) / 2; while (i > 0 && halda[up].cas > halda[i].cas) { halda_swap(i, up); i = up; up = (i - 1) / 2; } } void halda_bublej_dolu(int i) { while (1) { int levy = 2*i + 1; int pravy = 2*i + 2; // Pokud nemáme syna -> končíme if (levy >= halda_prvku) break; // Pokud máme jen jednoho syna -> porovnáme se s ním a končíme if (pravy == halda_prvku) { if (halda[levy].cas < halda[i].cas) halda_swap(i, levy); break; } // Pokud máme oba syny větší -> končíme if (halda[i].cas <= halda[levy].cas && halda[i].cas <= halda[pravy].cas) break; // Jinak se prohodíme s menším ze synů: if (halda[levy].cas <= halda[pravy].cas) { halda_swap(i, levy); i = levy; } else { halda_swap(i, pravy); i = pravy; } } } void halda_vloz(int i, int cas) { halda[halda_prvku].mesto = i; halda[halda_prvku].cas = cas; mesto[i].halda_index = halda_prvku; halda_bublej_nahoru(halda_prvku++); } int halda_getmin() { halda_swap(0, halda_prvku - 1); halda_prvku--; halda_bublej_dolu(0); return halda[halda_prvku].mesto; } void halda_update(int index, int cas) { if (cas < halda[index].cas) { halda[index].cas = cas; halda_bublej_nahoru(index); } else if (cas > halda[index].cas) { halda[index].cas = cas; halda_bublej_dolu(index); } } //////////////////////////////////////////////////////////////////////////////// /// Výkonná část void spocti_cas_dal(int i) { // Pokud přijedeme ještě před první "otevírací dobou", musíme na ní počkat: if (mesto[i].cas < mesto[i].offset) { mesto[i].cas_dal = mesto[i].offset; return; } // Jinak si zjistíme, v jaké fázi jsem dorazili: int cas_v_intervalu = (mesto[i].cas - mesto[i].offset) % mesto[i].interval; if (cas_v_intervalu <= mesto[i].delka) { // Můžeme jet dál hned mesto[i].cas_dal = mesto[i].cas; } else { // Připočteme čas do konce aktuálního intervalu mesto[i].cas_dal = mesto[i].cas + (mesto[i].interval - cas_v_intervalu); } } int main(void) { // A) Načtení vstupu scanf("%d %d %d %d", &N, &M, &start, &cil); // 1. Vyrobíme si pole měst se zatím prázdnými seznamy sousedů mesto = malloc(sizeof(t_mesto) * N); for (int i = 0; i < N; i++) { scanf("%d %d %d", &mesto[i].interval, &mesto[i].delka, &mesto[i].offset); mesto[i].sousede = NULL; } // 2. Načíteme hrany for (int i = 0; i < M; i++) { int odkud, kam, delka; scanf("%d %d %d", &odkud, &kam, &delka); t_hrana *hrana = malloc(sizeof(t_hrana)); hrana->kam = kam; hrana->delka = delka; hrana->dalsi = mesto[odkud].sousede; mesto[odkud].sousede = hrana; } // B) Dijkstrův algoritmus // 1.Vyrobíme si pole pro haldu halda = malloc(sizeof(t_halda) * N); // 2. Nastavení úvodních vzdáleností a vložení prvního města do haldy for (int i = 0; i < N; i++) { mesto[i].cas = INT_MAX; mesto[i].cas_dal = INT_MAX; mesto[i].halda_index = -1; } mesto[start].cas = 0; mesto[start].cas_dal = 0; halda_vloz(start, 0); // 3. Cyklus dokud není halda prázdná while (halda_prvku > 0) { int i = halda_getmin(); t_hrana *hrana = mesto[i].sousede; while (hrana != NULL) { // Update, pokud se do města umíme dostat dříve if (mesto[i].cas_dal + hrana->delka < mesto[hrana->kam].cas) { mesto[hrana->kam].odkud = i; mesto[hrana->kam].cas = mesto[i].cas_dal + hrana->delka; spocti_cas_dal(hrana->kam); if (mesto[hrana->kam].halda_index == -1) halda_vloz(hrana->kam, mesto[hrana->kam].cas_dal); else halda_update(mesto[hrana->kam].halda_index, mesto[hrana->kam].cas_dal); } hrana = hrana->dalsi; } } // C) Vypsání výstupu printf("%d\n", mesto[cil].cas); // Nasypeme cestu do pole a pak ji vypíšeme: int *vystup = malloc(sizeof(int) * N); int i = cil; int j = 0; while (i != start) { vystup[j++] = i; i = mesto[i].odkud; } printf("%d", start); for (int i = j - 1; i >= 0; i--) printf(" %d", vystup[i]); printf("\n"); return 0; }