Strona główna » Algorytmy » Artykuły » Drzewa i Grafy
 

Drzewa i Grafy

Drzewo

Drzewo to taki graf, którego wszystkie wierzchołki są połączone, a pomiędzy dwoma dowolnymi wierzchołkami istnieje dokładnie jedna ścieżka. W takim grafie nie występują cykle. Innymi słowy graf musi być spójny i acykliczny.

Przykład

Poniższy graf nie może być drzewem, ponieważ zawiera on przykładowo cykl ACFD, a ponadto nie jest spójny. Istnieją dwie oddzielne części grafu: ABCDEF oraz GH.

Z kolei poniższy graf jest drzewem:

Nie można tutaj znaleźć cykli, a wszystkie wierzchołki są połączone w spójną całość. Oznacza to też, że pomiędzy dwoma wierzchołkami istnieje dokładnie jedna i tylko jedna droga.

Analiza problemu

Jednym ze sposobów na sprawdzenie czy graf jest drzewem polega na wykorzystaniu algorytmu BFS. W tym przypadku należałoby zbierać o każdym kolejnym wierzchołki dwie informacje: poprzednika oraz czy dany wierzchołek został już odwiedzony. Algorytm można rozpocząć w dowolnym wierzchołku - nie wpłynie to w jakikolwiek sposób na wynik. Podczas odwiedzania wierzchołka należy uważnie odwiedzać jego sąsiadów. Otóż jeśli sąsiad do odwiedzenia jest już odwiedzony, ale nie jest to poprzednik to znaczy, że w grafie występuje cykl! Nie będzie to wtedy drzewo. Ponadto na koniec algorytmu należy sprawdzić czy wszystkie wierzchołki zostały odwiedzone, aby potwierdzić też warunek spójności.

Implementacja

Poniższa funkcja czyDrzewo() na podstawie przekazanej macierzy zwraca informację czy podany graf jest drzewem.

  1. static bool czyDrzewo(int[,] macierz) {
  2.   dane[] tab = new dane[macierz.GetLength(0)];
  3.   for (int i = 0; i < macierz.GetLength(0); i++) {
  4.     tab[i].odwiedzony = false;
  5.     tab[i].poprzednik = -1;
  6.   }
  7.   Queue<int> queue = new Queue<int>();
  8.   queue.Enqueue(0);
  9.   while (queue.Count != 0) {
  10.     int u = queue.Dequeue();
  11.     tab[u].odwiedzony = true;
  12.     for (int i = 0; i < macierz.GetLength(0); i++) {
  13.       if (macierz[u, i] > 0) {
  14.         if (tab[i].odwiedzony && i != tab[u].poprzednik) {
  15.           return false;
  16.         }
  17.         else if (!tab[i].odwiedzony) {
  18.           tab[i].poprzednik = u;
  19.           queue.Enqueue(i);
  20.         }
  21.       }
  22.     }
  23.   }
  24.   for (int i = 0; i < macierz.GetLength(0); i++) {
  25.     if (!tab[i].odwiedzony) {
  26.       return false;
  27.     }
  28.   }
  29.   return true;
  30. }

Funkcja wykorzystuje algorytm BFS. Początkowo wszystkie wierzchołki nie mają ustalonego poprzednika oraz nie są odwiedzone. Jako punkt początkowy jest wybierany pierwszy wierzchołek. Następnie odwiedzani są wszyscy kolejni sąsiedzi z którymi wierzchołek ma połączenie. Podczas przechodzenia sprawdzane jest czy nie występują cykle. Na koniec sprawdzana jest spójność. Jeśli algorytm nie zostanie przerwany to na koniec można zwrócić prawdę.

Testowanie funkcji

Do przetestowania funkcji można skorzystać z poniższego fragmentu kodu:

  1. static void Main(string[] args) {
  2.   Console.Write("Podaj ile jest wierzchołków w grafie\n n = ");
  3.   int n = Convert.ToInt32(Console.ReadLine());
  4.   int[,] macierz = new int[n, n];
  5.   for (int i = 0; i < n; i++) {
  6.     string[] str = Console.ReadLine().Split(' ');
  7.     for (int j = 0; j < n; j++) {
  8.       macierz[i, j] = Convert.ToInt32(str[j]);
  9.     }
  10.   }
  11.   bool wynik = czyDrzewo(macierz);
  12.   Console.WriteLine("Graf{0} jest drzewem", wynik ? "" : " nie");
  13.   Console.ReadKey();
  14. }

Graf należy podać w formie macierzy takiej jak poniżej:

  1. 0 1 1 1 0 0 0 0
  2. 1 0 0 0 0 0 0 0
  3. 1 0 0 0 0 0 0 0
  4. 1 0 0 0 0 1 0 1
  5. 0 0 0 0 0 1 0 0
  6. 0 0 0 1 1 0 0 0
  7. 0 0 0 0 0 0 0 1
  8. 0 0 0 1 0 0 1 0

Graf ten reprezentuje przykład poprawnego grafu - drzewa na początku artykułu.

Zadania
Zadanie 1
Kod źródłowy Zadanie 1Kod źródłowy Zadanie 1Kod źródłowy Zadanie 1