Przeskocz do treści

Delta mi!

Informatyczny kącik olimpijski

Przepływ w sieci

Tomasz Kulczyński

o artykule ...

  • Publikacja w Delcie: czerwiec 2011
  • Publikacja elektroniczna: 31-05-2011
  • Wersja do druku [application/pdf]: (72 KB)

Jednym z zadań, które zostały postawione przed uczestnikami akademickich drużynowych zawodów programistycznych ACM ICPC Dhaka Regional Contest 2010, było zadanie o nieco mylącym tytule Network Flow (Przepływ w sieci).

Trochę zagmatwaną treść zadania można streścić w następujący sposób: mamy dany math-wierzchołkowy graf nieskierowany math  w którym każdy z wierzchołków utożsamiamy z pewnym, zadanym punktem na płaszczyźnie. Stopień każdego wierzchołka (czyli liczba krawędzi z nim incydentnych) to math lub math Naszym zadaniem jest znaleźć taki cykl Eulera w math  (tj. cykl, który przechodzi każdą krawędzią dokładnie raz), którego koszt jest minimalny. Kosztem cyklu nazywamy sumę kątów pomiędzy każdą parą kolejnych krawędzi cyklu, przy czym interesują nas najmniejsze kąty pomiędzy prostymi zawierającymi pary kolejnych krawędzi.

Najprostszym rozwiązaniem jest przejrzenie wszystkich możliwości połączeń par krawędzi w każdym wierzchołku stopnia math Dla każdego układu połączeń sprawdzamy, czy tworzy on cykl Eulera, a jeśli tak, to obliczamy jego koszt. Niestety, takie rozwiązanie ma złożoność czasową math  Tak od razu nie widać metody na szybkie znalezienie najtańszego cyklu Eulera, podejdźmy zatem do problemu od innej strony. Możemy, na przykład, spróbować stworzyć jakikolwiek cykl Eulera, a później stopniowo zmniejszać jego sumaryczny koszt. Autor tego kącika nie ma jednak pomysłu na szybkie rozwiązanie problemu tym sposobem.

Podejście odwrotne daje natomiast rezultaty. Spróbujmy utworzyć ze wszystkich krawędzi grafu math  możliwie najtańszy zbiór cykli, a później najmniejszym kosztem pozmieniać połączenia w poszczególnych wierzchołkach tak, by powstał cykl Eulera. Na początku w każdym wierzchołku stopnia math łączymy krawędzie w pary tak, aby suma kosztów była jak najmniejsza. W ten sposób otrzymujemy zbiór cykli math o minimalnym możliwym koszcie. Zauważmy teraz, że jeśli dwa cykle math  i math z tego zbioru przechodzą przez ten sam wierzchołek math to – poprzez dowolną zamianę połączeń w wierzchołku math na inne – łączymy te dwa cykle w jeden. Oznaczmy minimalny koszt takiej zmiany w wierzchołku math przez math Jeśli zaś zmienimy połączenia w wierzchołku, który należy do jednego cyklu (przy czym cykl przechodzi przez niego dwukrotnie), to albo nic się nie zmieni, albo podzielimy tenże cykl na dwa.

Stwórzmy teraz nowy multigraf math  w którym wierzchołkami są cykle ze zbioru math a krawędziami wierzchołki stopnia math z math – przez każdy taki wierzchołek przechodzą wszakże dokładnie dwa cykle (niekoniecznie różne). Kosztem krawędzi odpowiadającej wierzchołkowi math z math  niech będzie math  Szukamy najtańszego sposobu połączenia wszystkich cykli w jeden, ale w multigrafie math  odpowiada to szukaniu zbioru krawędzi o minimalnym koszcie łączącego wszystkie wierzchołki. Jest to zatem problem wyznaczenia najtańszego drzewa rozpinającego w math  Zauważmy, że gdyby krawędzie math  mogły mieć ujemne koszty, to takie rozwiązanie nie działałoby, gdyż, być może, opłacałoby się wybrać, poza drzewem rozpinającym, jeszcze trochę krawędzi z math  które zmniejszyłyby koszt. U nas jednak math dla każdego wierzchołka math z math  Znanych jest kilka efektywnych algorytmów znajdujących minimalne drzewo rozpinające, np. algorytmy Kruskala i Prima, działające dla grafu math  w czasie math  Całe rozwiązanie zadania wymaga zbudowania grafu math  (koszt liniowy), a następnie znalezienia minimalnego drzewa rozpinającego w math  co możemy wykonać w czasie math  Takie rozwiązanie w żaden sposób nie korzysta ze specyfiki danych wejściowych, w szczególności z geometrycznych własności grafu oraz sposobu obliczania kosztów. Autor nie zna rozwiązania, które w istotny sposób korzystałoby z tych informacji, zachęca więc Czytelnika do próby znalezienia takowego.