Delta 9/2024

Szerokość ścieżkowa

Rewolucja! W królestwie Bajtocji wynaleziono telefon, i młody król, który właśnie zasiadł na tronie, chce wykorzystać ten wspaniały wynalazek do usprawnienia komunikacji w swoim królestwie. Dawniej każdą wiadomość przenosił gołąb pocztowy, a jak powszechnie wiadomo, jest to system dość wolny i zawodny. Król zarządził zatem zainstalowanie telefonu w każdym mieście. Kiedy jednak jego doradcy pokazali mu kosztorys projektu, król złapał się za głowę i zdecydował na inne rozwiązanie: aparaty mają być zainstalowane w taki sposób, by wszyscy poddani mieli dostęp do telefonu w swoim mieście lub w pewnym innym mieście połączonym bezpośrednio drogą z ich miastem. Doradcy króla głowią się teraz, w których miastach je zainstalować, tak aby było ich jak najmniej i tym samym koszt projektu był jak najniższy.

Przedstawmy nasz problem w języku teorii grafów. Rozważmy graf G=(V,E), w którym zbiór wierzchołków V reprezentuje miasta w królestwie, a zbiór krawędzi E odpowiada istniejącym połączeniom drogowym. Chcemy znaleźć taki podzbiór wierzchołków D, by każdy wierzchołek grafu albo sam należał do zbioru D, albo miał sąsiada w zbiorze D. Każdy wierzchołek o takiej własności nazwiemy zdominowanym. W opisanej sytuacji zdominowane są wszystkie wierzchołki, podzbiór D nazwiemy więc zbiorem dominującym. Oczywiście, wybierając D=V, wskażemy poprawny zbiór dominujący, ale, podobnie jak króla, interesuje nas zbiór o możliwie najmniejszej liczbie wierzchołków.

Opisany problem w teorii grafów nosi nazwę problemu minimalnego zbioru dominującego. Możemy także rozważyć wariant, gdy koszty wybudowania telefonu w poszczególnych miastach się różnią – każdemu miastu vi przypisujemy koszt c(vi), który będziemy też nazywać wagą. Naszym zadaniem jest wtedy wskazanie zbioru dominującego o minimalnej sumarycznej wadze. Jest to wówczas problem zbioru dominującego o minimalnej wadze.

Naturalnym pomysłem w przypadku tego typu problemów jest podejście zachłanne, w którym zaczynamy od pustego zbioru D i kolejno dodajemy do niego wierzchołki, które wydają się najbardziej przybliżać nas do celu. Powiedzmy, że jesteśmy w trakcie takiej procedury, i przez Z oznaczmy zbiór wierzchołków zdominowanych, czyli należących w danym momencie do zbioru D (który na koniec tej procedury będzie zbiorem dominującym), lub posiadających sąsiada w zbiorze D. Początkowo zbiór Z jest pusty. W każdym kroku wybieramy wierzchołek, który nie należy do zbioru Z i ma największą liczbę sąsiadów nienależących do zbioru Z. Taki wierzchołek dodajemy do zbioru D – wtedy on i wszyscy jego sąsiedzi trafiają do zbioru Z. Postępujemy w ten sposób, dopóki wszystkie wierzchołki G nie zostaną włączone do Z. Wydawałoby się, że takie podejście to dobry pomysł, jako że w każdym kroku zwiększamy Z o maksymalną w tym momencie liczbę wierzchołków. Istnieją jednak grafy, dla których to podejście nie jest optymalne:

image

W powyższym przykładzie najpierw włączymy do grafu niebieski wierzchołek. Wtedy żółte wierzchołki zostaną zdominowane. W kolejnych krokach nasz algorytm włoży wszystkie trzy szare wierzchołki do zbioru dominującego. W ten sposób otrzymamy zbiór dominujący o mocy 4. Zauważmy jednak, że zbiór żółtych wierzchołków jest poprawnym zbiorem dominującym o mocy 3.

Obydwa opisane problemy możemy rozwiązać, rozważając wszystkie możliwe podzbiory wierzchołków grafu, sprawdzając, które z nich są zbiorami dominującymi, i wybierając najmniejszy z nich. Złożoność czasowa tego algorytmu to O(2|V||E|), co zdecydowanie nie jest satysfakcjonujące (dla grafu o zaledwie 20 wierzchołkach 2|V||E| może być równe prawie 200 milionów!). Czy jesteśmy w stanie zaproponować zatem szybsze, tj. wielomianowe rozwiązanie? Nie spodziewamy się, by odpowiedź była pozytywna – obydwa te problemy są NP-trudne. Z drugiej strony potrzebujemy umieć szybko i efektywnie rozwiązywać to zadanie, ponieważ występuje w wielu rzeczywistych scenariuszach związanych z dystrybucją zasobów.

Jednym ze sposobów radzenia sobie z NP-trudnymi problemami grafowymi jest uważne przyjrzenie się grafom, dla których potrzebujemy znaleźć rozwiązanie – być może mają one dodatkowe przydatne własności. Przykładowo wiemy, że w grafie miast połączonych drogami bez mostów, tuneli ani skrzyżowań nie można znaleźć pięciu miast połączonych każde z każdym (korzystamy tutaj z twierdzenia Kuratowskiego charakteryzującego grafy planarne).

Znając lepiej własności grafów, dla których mamy rozwiązywać nasz problem, możemy projektować algorytmy korzystające z tych własności i działające szybciej niż algorytm rozwiązujący nasz problem dla dowolnego grafu.

Przypadek ścieżki

Rozważmy graf, który jest ścieżką (patrz rysunek na marginesie). Oznaczmy jego kolejne wierzchołki przez v1, v2, , vn. Jak rozwiązać zagadnienie minimalnego zbioru dominującego dla ścieżek? Jeżeli wierzchołki nie mają wag, możemy po prostu wybrać co trzeci wierzchołek, zaczynając od drugiego wierzchołka ścieżki.

W przypadku ważonym nasze zadanie się nieco komplikuje, ale nadal istnieje algorytm liniowy znajdujący optymalne rozwiązanie. Dla każdego i{1,2,,n} rozważmy optymalny zbiór dominujący dla ścieżki złożonej z wierzchołków v1v2vi w każdym z trzech scenariuszy:

  • wierzchołek vi należy do zbioru dominującego;

  • vi nie należy do zbioru dominującego, ale jego sąsiad vi1 już tak;

  • zarówno vi, jak i vi1 nie należą do zbioru dominującego (zauważmy, że w tym przypadku wierzchołek vi nie jest zdominowany).

Oznaczmy optymalny zbiór dominujący dla ścieżki v1v2vi dla każdego z trzech wyżej opisanych przypadków jako, odpowiednio, Di1,Di2,Di3, a przez k(Dij) oznaczmy sumaryczny koszt wierzchołków w zbiorze Dij. Zauważmy, że jeśli mamy już znalezione optymalne zbiory dla i w każdym scenariuszu, możemy łatwo znaleźć wyniki dla i+1.

  • Niech j=argminj=1,2,3 k(Dij). Wtedy Di+11=Dij{vi+1}.

  • Z definicji zachodzi Di+12=Di1.

  • W ostatnim scenariuszu wierzchołki vivi+1 nie należą do zbioru dominującego, zatem wierzchołek vi musi być zdominowany przez wierzchołek vi1. Zatem zachodzi Di+13=Di2.

Aby znaleźć najlepsze rozwiązanie dla całej ścieżki, wybieramy rozwiązanie o mniejszej sumarycznej wadze dla i=n spośród pierwszych dwóch scenariuszy (w ostatnim wierzchołek vn nie byłby dominowany). Dopracowanie szczegółów i dowód poprawności algorytmu pozostawiamy Czytelnikowi.

Szerokość ścieżkowa

Dla ogólnych grafów nie możemy niestety skorzystać z tego algorytmu, bo wierzchołki mogą być ze sobą połączone w znacznie bardziej skomplikowany sposób. Rodzi się jednak pytanie, co w przypadku, gdy rozważany graf jest podobny do ścieżki (np. tak jak grafy przedstawione na obrazkach na marginesie). Może potrafilibyśmy wykorzystać nasze zrozumienie problemu dla ścieżek do skonstruowania algorytmu dla grafów przypominających ścieżki?

Zanim pójdziemy dalej, musimy sformalizować pojęcie podobieństwa do ścieżki. Dekompozycją ścieżkową (ang. path decomposition) grafu G nazywamy parę (P,{β(u)}uV(P)), gdzie P jest ścieżką, a każdemu wierzchołkowi u przyporządkowany jest zbiór β(u)V(G) (zwany workiem) tak, że spełnione są następujące dwa warunki:

  • dla każdych dwóch wierzchołków v1v2 połączonych krawędzią w grafie G istnieje wierzchołek uV(P), którego worek zawiera v1v2;

  • dla każdego wierzchołka v grafu G zbiór wierzchołków P, których worki zawierają v, tworzy niepusty, spójny podgraf P (czyli w tym przypadku ścieżkę).

Szerokość dekompozycji ścieżkowej (P,{β(u)}uV(P)) to maxuV(P)|β(u)|1. Szerokością ścieżkową (ang. pathwidth) grafu G nazywamy minimalną możliwą szerokość dekompozycji ścieżkowej grafu G. W definicji odejmujemy 1, by ścieżki miały szerokość ścieżkową równą 1, a nie 2.

Okazuje się, że szerokość ścieżkowa wielu grafów rozważanych w rzeczywistych scenariuszach jest mała (czyli ograniczona przez pewną stałą). Jest to bardzo wygodne, gdyż możemy wykorzystać tę własność do projektowania szybkich algorytmów.

W dalszej części artykułu skoncentrujemy się na problemie najmniejszego zbioru dominującego w grafie bez wag. Algorytm, który podamy, można łatwo zmodyfikować, aby działał również w przypadku grafów z wagami, jednak pominiemy te szczegóły, aby idea algorytmu była bardziej przejrzysta.

Gdy konstruowaliśmy zbiór dominujący o minimalnej wadze dla ścieżki, w momencie i+1 nie potrzebowaliśmy wiedzieć, jak wygląda cały optymalny zbiór dominujący dla ścieżki złożonej z pierwszych i wierzchołków – korzystaliśmy jedynie z wiedzy o wierzchołkach vi1 oraz vi. Wykorzystamy teraz podobną intuicję, konstruując algorytm dynamiczny, który będzie działać dla grafów o ustalonej szerokości ścieżkowej – będziemy pamiętać minimalny koszt zbioru dominującego dla różnych możliwych stanów wierzchołków należących do obecnie rozważanego worka.

Rozważmy graf G i jego dekompozycję ścieżkową (P,{β(u)}uV(P)), gdzie P jest ścieżką u1u2up. Przez ki oznaczmy |β(ui)|, a przez k=maxi=1,,nki oznaczmy szerokość ścieżkową P powiększoną o 1. Dla każdego wierzchołka v grafu G rozróżniamy jeden z trzech możliwych stanów:

  1. v należy do zbioru dominującego;

  2. v nie należy do zbioru dominującego, ale jest zdominowany przez co najmniej jednego ze swoich sąsiadów;

  3. v nie należy do zbioru dominującego i nie jest zdominowany przez żadnego ze swoich sąsiadów.

Będziemy konstruować najmniejszy zbiór dominujący, tak jak poprzednio, rozważając kolejne wierzchołki P wraz z przypisanymi im workami. Dla worka i rozważamy wszystkie możliwe konfiguracje stanów jego wierzchołków. Jest ich 3ki – każdą konfigurację możemy reprezentować przez wektor α=(s1,s2,,ski), gdzie sj{1,2,3} dla j{1,,ki}. Rodzinę wszystkich możliwych wektorów stanów worka β(ui) oznaczymy jako Si.

Najpierw generujemy (czyli rozpatrujemy) wszystkie możliwe stany dla pierwszego worka β(u1). Przez c(α) dla αS1 oznaczmy liczbę wierzchołków, które przy stanie α należą do zbioru dominującego. Może się jednak zdarzyć, że wektor α reprezentuje niepoprawną konfigurację, np. gdy istnieje wierzchołek w stanie 2, którego żaden sąsiad nie należy do zbioru dominującego (żaden nie jest w stanie 1). Niepoprawnym wektorom α przypisujemy c(α)=. To pozwala nam zainicjować algorytm programowania dynamicznego.

Załóżmy teraz, że dla każdego wektora αSi mamy obliczony c(α) – rozmiar minimalnego zbioru dominującego w grafie indukowanym przez wierzchołki należące do β(u1)β(u2)β(ui), który zgadza się ze stanami opisanymi wektorem α (jeśli taki zbiór dominujący nie istnieje albo gdy konfiguracja jest niepoprawna, to bierzemy c(α)=).

Chcielibyśmy teraz obliczyć wyniki dla stanów należących do Si+1. Przedtem przejrzymy jednak jeszcze raz nasze wyniki dla Si. Popatrzmy na wierzchołki należące do β(ui), ale nienależące do β(ui+1). Z własności dekompozycji ścieżkowej wiemy, że nie mają one sąsiadów w β(ui+1)β(ui+2)β(up) poza tymi znajdującymi się już w β(u1)β(u2)β(ui). W związku z tym każdy taki wierzchołek musi już należeć do zbioru dominującego albo być zdominowany, jako że w kolejnych krokach nie będziemy rozważali ich żadnych ,,nowych” sąsiadów. Zatem każdemu wektorowi α, w którym jeden z wierzchołków ze zbioru β(ui)β(ui+1) jest w stanie 3, przypisujemy c(α)=.

Teraz możemy w końcu dodać nowe wierzchołki. Rozważmy wszystkie możliwe konfiguracje wierzchołków należących do β(ui) poszerzone o konfiguracje wierzchołków z β(ui+1)β(ui). Możemy wtedy obliczyć wartość c dla takich rozszerzonych konfiguracji: w przypadku konfiguracji poprawnych zwiększając wartość o liczbę wierzchołków, którym przypisano stan 1, a w przypadku konfiguracji niepoprawnych utrzymując przypisanie . Zauważmy teraz, że jeśli zapomnimy we wszystkich konfiguracjach o wierzchołkach należących do β(ui), ale nienależących do β(ui+1), to otrzymamy zbiór wszystkich konfiguracji Si+1 wraz z obliczonymi dla nich wartościami funkcji c.

Obliczamy w ten sposób wyniki dla kolejnych i=2,3,,p. Aby znaleźć minimalny wynik dla całego grafu G, rozważamy wszystkie poprawne konfiguracje dla β(up), w których każdy wierzchołek jest w stanie 1 lub 2, i wybieramy tę, dla której wartość funkcji c jest najmniejsza. Znaleźliśmy zatem liczność minimalnego zbioru dominującego. Jaka jest złożoność czasowa naszego algorytmu? Każdy krok, czyli wygenerowanie wszystkich stanów dla worka oraz sprawdzenie ich poprawności, wykonujemy w czasie O(3k). Wykonamy p2n kroków – tyle, ile wynosi długość ścieżki P. Nasz algorytm działa zatem w czasie O(n3k). Dla grafów o małej szerokości ścieżkowej jest to zatem znacznie lepszy czas niż opisany na początku algorytm działający w czasie O(2|V||E|) (dla grafów o 20 wierzchołkach i gdy k=5, liczba n3k nie przekracza 5 tysięcy).

Opisana tutaj metoda ma też zastosowanie dla innych problemów NP-trudnych, w których szukamy algorytmów dynamicznych na dekompozycji ścieżkowej. W połączeniu z algorytmem obliczającym prawie optymalną dekompozycję ścieżkową (jest niestety dość skomplikowany, przez co musimy go pominąć) jesteśmy w stanie skonstruować algorytmy działające w czasie wielomianowym dla grafów o szerokości ścieżkowej ograniczonej przez stałą.

Okazuje się również, że grafy o małej szerokości ścieżkowej pojawiają się w prawdziwym życiu. Przykładowo, w przetwarzaniu języka naturalnego zdania można modelować jako grafy, gdzie wierzchołki odpowiadają pojedynczym słowom, zaś krawędź oznacza jakiś rodzaj zależności między słowami (np. przymiotnik modyfikujący znaczenie rzeczownika). Eksperymenty pokazują, że takie grafy mają na ogół niską szerokość ścieżkową – lingwiści twierdzą, że gdyby przekraczała ona 6, to ludzie mieliby problem z rozumieniem mowy.

Na koniec dodajmy, że szerokość ścieżkowa została zaproponowana przez Neila Robertsona i Paula Seymoura w ich słynnym cyklu artykułów zatytułowanych Graph Minors. Prawdziwą rewolucją na salonach okazał się jednak inny, wprowadzony przez nich parametr uogólniający szerokość ścieżkową: szerokość drzewiasta. To jednak temat na kolejny artykuł.