Advertisement
PseudoInformatyk

Dijkstra

Jan 20th, 2020
161
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 12.65 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using Priority_Queue;
  5.  
  6. //Problem 1 - „Misja”
  7.  
  8. //Jest XXXIII wiek.Ludzie podróżują ultra-szybkimi statkami kosmicznymi pomiędzy zawieszonymi
  9. //w przestrzeni międzygwiezdnej ogromnymi hipermiastami.Kosmos jest w stanie wojny i dowolne
  10. //podróżowanie w przestrzeni kosmicznej jest zabronione. Do komunikacji służą tylko specjalnie
  11. //wybrane korytarze komunikacyjne łączące ze sobą hipermiasta. W tych korytarzach statki
  12. //kosmiczne poruszają się z prędkością światła, jednak odległości między hipermiastami są duże –
  13. //liczone zwykle w godzinach świetlnych.Stąd podróże trwają pewien czas.Niektóre hipermiasta są
  14. //jednak połączone specjalnymi tunelami czasoprzestrzennymi i dzięki temu podróż między nimi nic
  15. //nie trwa (!). Takich tuneli w całej przestrzeni jest jednak co najwyżej 50. Z racji tego, że trwa
  16. //kosmiczna wojna, to działania szpiegowskie są zakrojone na dużą skalę.Pewien szpieg znajduje się
  17. //w pierwszym hipermieście i ma za zadanie wykraść tajne informacje, które są ukryte w ostatnim z
  18. //hipermiast.W związku z tym musi przemieścić się on z hipermiasta nr 1 do hipermiasta nr n.Po
  19. //drodze może on swobodnie poruszać się zwykłymi korytarzami.Jednak podróżowanie tunelami
  20. //czasoprzestrzennymi jest niebezpieczne ze względu na ich niestabilność – szpieg może po prostu
  21. //zniknąć w wyższym wymiarze. Nie da się jednak ukryć, że tunele mogą pomóc w szybszym
  22. //pokonywaniu trasy. Szpieg stosuje w związku z tym zasadę ograniczania ryzyka i w czasie całej
  23. //podróży pozwala sobie na skorzystanie z co najwyżej k różnych tuneli czasoprzestrzennych (z
  24. //każdego po razie). Misja jest krytyczna i od jej powodzenia mogą zależeć losy wszechświata.
  25. //Szpieg musi ją wykonać w jak najkrótszym czasie.Czy pomożesz mu w wykonaniu zadania i
  26. //znalezienia najkrótszej czasowo trasy?
  27.  
  28. //Wejście:
  29. //W pierwszej linii wejścia podana jest liczba n hipermiast, m korytarzy oraz maksymalną liczbę k
  30. //tuneli czasoprzestrzennych, których można użyć (1<n<=10000, 1<=m<=100000, 1<=k<=3). W
  31. //kolejnych m liniach są podane informacje dotyczące korytarzy: po 3 liczby całkowite oznaczające
  32. //odpowiednio numery połączonych miast oraz długość korytarza(co najwyżej 100 godzin
  33. //świetlnych).
  34.  
  35. //Wyjście:
  36. //W pierwszej linii wyjście należy podać czas optymalnej trasy, a w kolejnej linii po kolei ciąg liczb
  37. //(numerów miast) opisujących trasę.
  38.  
  39. //Przykład:
  40.  
  41. //Wejście:
  42. //5 7 1
  43. //1 3 3 //między 1 i 3 korytarz powietrzny o długości 3 godzin świetl
  44. //2 4 2 //itd.
  45. //2 3 3
  46. //1 2 0 //tunel czasoprzestrzenny
  47. //3 4 0 //tunel czasoprzestrzenny
  48. //3 5 3
  49. //4 5 2
  50.  
  51. //Wyjście:
  52. //4
  53. //1 2 4 5
  54.  
  55. namespace Dijkstra
  56. {
  57.     class Trasa
  58.     {
  59.         public int koncowy;
  60.         public int koszt;
  61.  
  62.         public Trasa(int koncowy, int koszt)
  63.         {
  64.             this.koncowy = koncowy;
  65.             this.koszt = koszt;
  66.         }
  67.     }
  68.  
  69.     class Poprzednik
  70.     {
  71.         public int poprzednik;
  72.         public bool zero;
  73.  
  74.         public Poprzednik(int poprzednik, bool zero)
  75.         {
  76.             this.poprzednik = poprzednik;
  77.             this.zero = zero;
  78.         }
  79.     }
  80.  
  81.     public class WezelZZero
  82.     {
  83.         public int wierzcholek;
  84.         public int ile_tuneli;
  85.  
  86.         public WezelZZero(int wierzcholek, int ile_tuneli)
  87.         {
  88.             this.wierzcholek = wierzcholek;
  89.             this.ile_tuneli = ile_tuneli;
  90.         }
  91.     }
  92.  
  93.     class Program
  94.     {
  95.         public static int licznik = 0;
  96.  
  97.         static void Main()
  98.         {
  99.             int wierzcholkow = 0, korytarzy = 0, tuneli = 0;
  100.             List<Trasa>[] lista = null;
  101.             Wczytywanie(ref lista, ref wierzcholkow, ref korytarzy, ref tuneli);
  102.             DateTime start = DateTime.Now;
  103.             Rozwiazanie(wierzcholkow, lista, tuneli);
  104.             DateTime koniec = DateTime.Now;
  105.             Console.WriteLine($"Liczba operacji elemntarnych: {licznik}");
  106.             Console.WriteLine($"Czas działnia programu: {(koniec - start).TotalMilliseconds} milisekund = {(koniec - start).TotalSeconds} sekund");
  107.             Console.ReadKey();
  108.         }
  109.  
  110.         static void Rozwiazanie(int wierzcholkow, List<Trasa>[] lista_incydencji, int tuneli)
  111.         {
  112.             int[,] d = new int[tuneli + 1, wierzcholkow]; //Tablica wag
  113.             Poprzednik[,] p = new Poprzednik[tuneli + 1, wierzcholkow]; //Poprzednicy (poprzednik i czy wykorzystany tunel do dojścia)
  114.             bool[,] odwiedzeni = new bool[tuneli + 1, wierzcholkow]; //Tablica odwiedzonych wierzchołków
  115.             SimplePriorityQueue<WezelZZero, int> kolejka_priorytetowa = new SimplePriorityQueue<WezelZZero, int>(); //Kolejka priorytetowa
  116.             for (int i = 0; i <= tuneli; i++) //Przypisanie zer i nieskończoności w tablicy wag
  117.             {
  118.                 for (int j = 0; j < wierzcholkow; j++)
  119.                 {
  120.                     if (j == 0) d[i, j] = 0;
  121.                     else d[i, j] = int.MaxValue;
  122.                 }
  123.             }
  124.             kolejka_priorytetowa.Enqueue(new WezelZZero(0, 0), 0); //Wierzchołek początkowy 0 z 0 przejściami przez tunele o wadze 0
  125.             while (kolejka_priorytetowa.Count != 0) //Dopóki jest jakiś wierzchołek w kolejce
  126.             {
  127.                 var wierzcholek = kolejka_priorytetowa.Dequeue(); //Zdjęcie z kolejki elementu o najwyższym priorytecie (najmniejsza odległość)
  128.                 odwiedzeni[wierzcholek.ile_tuneli, wierzcholek.wierzcholek] = true; //Wierzchołek w którym jesteśmy zaznaczamy jako odwiedzony (ile tuneli/wierzchołek)
  129.                 if (wierzcholek.wierzcholek == wierzcholkow - 1) break; //Jeżeli jesteśmy w ostatnim wierzchołku to nic się nie zmieni więc nie idziemy dalej
  130.                 foreach (Trasa docelowy_wierzcholek in lista_incydencji[wierzcholek.wierzcholek]) //Dla danego wierzchołka sprawdzamy każdego jego sąsiada
  131.                 {
  132.                     licznik++;
  133.                     if (odwiedzeni[wierzcholek.ile_tuneli, docelowy_wierzcholek.koncowy] == false) //Jeżeli wierzchołek, do którego chcemy iść nie został jeszcze odwiedzony
  134.                     {
  135.  
  136.                         if (docelowy_wierzcholek.koszt == 0 && wierzcholek.ile_tuneli != tuneli) //Jeżeli koszt to 0 i liczba tuneli nie przekracza max tuneli
  137.                         {
  138.                             if (d[wierzcholek.ile_tuneli, wierzcholek.wierzcholek] < d[wierzcholek.ile_tuneli + 1, docelowy_wierzcholek.koncowy]) //Jeżeli trasa z nie przejściem przez tunel jest gorsza od trasy z przejściem przez tunel to jej nie bierzemy, nie wykroczy poza tablice bo tuneli != tuneli
  139.                             {
  140.                                 d[wierzcholek.ile_tuneli + 1, docelowy_wierzcholek.koncowy] = d[wierzcholek.ile_tuneli, wierzcholek.wierzcholek]; //Sprawdza, czy nie ma już innej lepszej trasy wykorzystującej tunel, jeżeli nie to wchodzimy, jeżeli jest inna, wykorzystująca tunel i jest lepsza to nie zmieniamy
  141.                                 p[wierzcholek.ile_tuneli + 1, docelowy_wierzcholek.koncowy] = new Poprzednik(wierzcholek.wierzcholek, true); //poprzednik TRUE - wykorzystuje tunel
  142.                                 var temp = new WezelZZero(docelowy_wierzcholek.koncowy, wierzcholek.ile_tuneli + 1); //Wstawienie na kolejke kolejnego elementu
  143.                                 if (kolejka_priorytetowa.Contains(temp)) kolejka_priorytetowa.UpdatePriority(temp, d[wierzcholek.ile_tuneli + 1, docelowy_wierzcholek.koncowy]); //Aktualizacja wag w kolejce
  144.                                 else kolejka_priorytetowa.Enqueue(temp, d[wierzcholek.ile_tuneli + 1, docelowy_wierzcholek.koncowy]); //Dodanie do kolejki
  145.                             }
  146.                         }
  147.                         else if (d[wierzcholek.ile_tuneli, wierzcholek.wierzcholek] + docelowy_wierzcholek.koszt < d[wierzcholek.ile_tuneli, docelowy_wierzcholek.koncowy] && docelowy_wierzcholek.koszt != 0) //Klasyczna Dijkstra - jeżeli droga z obecnego do końcowego plus koszt jest mniejsza od wagi końcowego to lecimy
  148.                         {
  149.                             d[wierzcholek.ile_tuneli, docelowy_wierzcholek.koncowy] = d[wierzcholek.ile_tuneli, wierzcholek.wierzcholek] + docelowy_wierzcholek.koszt;
  150.                             p[wierzcholek.ile_tuneli, docelowy_wierzcholek.koncowy] = new Poprzednik(wierzcholek.wierzcholek, false);
  151.                             var temp = new WezelZZero(docelowy_wierzcholek.koncowy, wierzcholek.ile_tuneli);
  152.                             if (kolejka_priorytetowa.Contains(temp)) kolejka_priorytetowa.UpdatePriority(temp, d[wierzcholek.ile_tuneli, docelowy_wierzcholek.koncowy]);
  153.                             else kolejka_priorytetowa.Enqueue(temp, d[wierzcholek.ile_tuneli, docelowy_wierzcholek.koncowy]);
  154.                         }
  155.  
  156.                     }
  157.                 }
  158.             }
  159.             Wypisywanie(d, p, wierzcholkow, tuneli);
  160.         }
  161.  
  162.         static void Wypisywanie(int[,] d, Poprzednik[,] p, int wierzcholkow, int tuneli)
  163.         {
  164.             int min = int.MaxValue;
  165.             int wiersz = 0;
  166.             for (int i = 0; i <= tuneli; i++) //Znalezienie wiersza z najmniejszą wartością w ostatniej kolumnie (ostatni wierzchołek)
  167.             {
  168.                 if (d[i, wierzcholkow - 1] < min)
  169.                 {
  170.                     min = d[i, wierzcholkow - 1];
  171.                     wiersz = i;
  172.                 }
  173.             }
  174.  
  175.             if (min == int.MaxValue) //Nie udało się dojść do ostatniego wierzchołka
  176.             {
  177.                 using (StreamWriter stw = new StreamWriter("out.txt"))
  178.                 {
  179.                     stw.WriteLine(min);
  180.                     Console.WriteLine(min);
  181.                     Console.WriteLine("");
  182.                     stw.WriteLine("");
  183.                 }
  184.                 return;
  185.             }
  186.  
  187.             Poprzednik temp = p[wiersz, wierzcholkow - 1]; //Poprzednik pobierany z tablicy
  188.             string wynik = wierzcholkow.ToString(); //Dodaje ostatni wierzchołek (5)
  189.  
  190.             while (temp != null) //Dopóki nie dojdziemy do końca poprzedników (0)
  191.             {
  192.                 wynik = (temp.poprzednik + 1).ToString() + " " + wynik; //Dodanie poprzednika+1 bo liczymy od 0
  193.                 if (temp.zero == true) wiersz--; //Jeżeli wystąpił tunel, to zmniejszamy wiersz o 1
  194.                 temp = p[wiersz, temp.poprzednik]; //Aktualizacja poprzednika
  195.             }
  196.  
  197.             using (StreamWriter stw = new StreamWriter("out.txt"))
  198.             {
  199.                 stw.WriteLine(min);
  200.                 Console.WriteLine(min);
  201.                 Console.WriteLine(wynik);
  202.                 stw.WriteLine(wynik);
  203.             }
  204.         }
  205.         static void Wczytywanie(ref List<Trasa>[] lista, ref int wierzcholkow, ref int korytarzy, ref int tuneli)
  206.         {
  207.             bool pierwsza_linia = true;
  208.             string line;
  209.             string[] tab = null;
  210.             int x = 0, y = 0, z = 0;
  211.             try
  212.             {
  213.                 using (StreamReader str = new StreamReader("in0.txt"))
  214.                 {
  215.                     while ((line = str.ReadLine()) != null)
  216.                     {
  217.                         tab = line.Split(' ');
  218.                         if (pierwsza_linia == true)
  219.                         {
  220.                             pierwsza_linia = false;
  221.                             wierzcholkow = Convert.ToInt32(tab[0]); //liczba wierzchołków
  222.                             korytarzy = Convert.ToInt32(tab[1]); //liczba korytarzy (połączeń)
  223.                             tuneli = Convert.ToInt32(tab[2]);
  224.                             lista = new List<Trasa>[wierzcholkow];
  225.                             for (int i = 0; i < wierzcholkow; i++)
  226.                             {
  227.                                 lista[i] = new List<Trasa>();
  228.                             }
  229.                         }
  230.                         else
  231.                         {
  232.                             x = Convert.ToInt32(tab[0]); //1 miasto
  233.                             y = Convert.ToInt32(tab[1]); //2 miasto
  234.                             z = Convert.ToInt32(tab[2]); //koszt połączenia
  235.                             lista[x - 1].Add(new Trasa(y - 1, z));
  236.                             lista[y - 1].Add(new Trasa(x - 1, z));
  237.                         }
  238.                     }
  239.                 }
  240.             }
  241.             catch (IOException)
  242.             {
  243.                 Console.WriteLine("File not found...");
  244.                 Console.ReadKey();
  245.                 System.Diagnostics.Process.GetCurrentProcess().Kill();
  246.                 //Environment.Exit(0);
  247.             }
  248.         }
  249.     }
  250. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement