Algorytm Kosaraju do znajdowania silnie spójnych składowych w grafie ( http://www.algorytm.org/algorytmy-grafowe/silnie-spojne-skladowe.html – tu są 2 implementacje rekurencyjne i DOKŁADNY OPIS) zaimplementowałem w wersji bez rekurencji.
Dalej nie wygląda to za przejrzyście, ale jeśli ktoś ma problem ze rozumieniem rekurencji to może pomóc.
/* "Program znajdujący silnie spójne składowe w grafie skierowanym - bez funkcji rekurencyjnych" Jerzy Skalski (phoowned@wp.pl) 2017-05-15 Wymagania programu: C++11 (opcja kompilatora) - można przepisać pętle po vectorach i listach tak, żeby nie był wymagany Opis wejścia: W pierwszej linii wejścia znajduje się jedna liczba dodatnia n - liczba wierzchołków grafu. Dalej następuje n linii; i-ta spośród tych linii ma postać k a1 a2 ... ak gdzie a1, a2, ..., ak to numery wierzchołków, do których prowadzą krawędzie z i-tego, zaś k jest liczbą tych wierzchołków. Przykładowe dane: 5 1 1 3 2 3 4 1 0 0 0 Rysunek grafu skierowanego: /<---< 2 <---<\ / \ 0 >-------------> 1 >--> 3 \ \>-> 4 Wynik: SSS ID: 0 1 2 0 SSS ID: 1 3 SSS ID: 2 4 */ #include <iostream> #include <map> #include <vector> #include <stack> #include <list> using namespace std; int main() { int iloscWezlow, iloscKrawedziWezla, wezel, wezelSasiedni, wezelStartowy, idSilnieSkladowej, i; vector<int>* listaSasiadowGraf; vector<int>* listaSasiadowGrafTransponowany; list<int> kolejnoscOdwiedzaniaDFSem; stack<int> wezlyDoOdwiedzenia; unsigned int* odwiedzoneWezly; cin >> iloscWezlow; // inicjujemy tablice listaSasiadowGraf = new vector<int>[iloscWezlow]; listaSasiadowGrafTransponowany = new vector<int>[iloscWezlow]; odwiedzoneWezly = new unsigned int[iloscWezlow]; // ladujemy krawedzie do grafu i grafu transponowanego for (wezel = 0; wezel < iloscWezlow; ++wezel) { cin >> iloscKrawedziWezla; for (i = 0; i < iloscKrawedziWezla; ++i) { cin >> wezelSasiedni; listaSasiadowGraf[wezel].push_back(wezelSasiedni); listaSasiadowGrafTransponowany[wezelSasiedni].push_back(wezel); } } for (wezel = 0; wezel < iloscWezlow; ++wezel) odwiedzoneWezly[wezel] = 0; // przegladamy wezly grafu DFSem // zapisujemy czas przetworzenia (kolejnosc odwiedzania post order - dodajemy do listy jak sie 'cofamy') for(wezelStartowy = 0; wezelStartowy < iloscWezlow; ++wezelStartowy) { if(odwiedzoneWezly[wezelStartowy]) continue; wezlyDoOdwiedzenia.push(wezelStartowy); while(!wezlyDoOdwiedzenia.empty()) { wezel = wezlyDoOdwiedzenia.top(); wezlyDoOdwiedzenia.pop(); if(odwiedzoneWezly[wezel]) { if(odwiedzoneWezly[wezel] == 1) { // push_front - powstanie lista od najwiekszego czasu przetworzenia kolejnoscOdwiedzaniaDFSem.push_front(wezel); odwiedzoneWezly[wezel] = 2; } continue; } odwiedzoneWezly[wezel] = 1; wezlyDoOdwiedzenia.push(wezel); for(int wezelSasiedni : listaSasiadowGraf[wezel]) { if(!odwiedzoneWezly[wezelSasiedni]) wezlyDoOdwiedzenia.push(wezelSasiedni); } } } for (wezel = 0; wezel < iloscWezlow; ++wezel) odwiedzoneWezly[wezel] = 0; // przegladamy wezly grafu transponowanego DFSem od najwiekszego czasu przetworzenia DFSem // wszystkie przejrzane w ten sposob wezly naleza do jednej silnie spójnej składowej idSilnieSkladowej = 0; for(int wezelStartowy : kolejnoscOdwiedzaniaDFSem) { if(odwiedzoneWezly[wezelStartowy]) continue; wezlyDoOdwiedzenia.push(wezelStartowy); cout << "SSS ID: " << idSilnieSkladowej << endl; // TUTAJ ZACZYNA SIE NOWA SSS while(!wezlyDoOdwiedzenia.empty()) { wezel = wezlyDoOdwiedzenia.top(); wezlyDoOdwiedzenia.pop(); if(odwiedzoneWezly[wezel]) { if(odwiedzoneWezly[wezel] == 1) { // przy ponownym wejsciu do wezla (cofajac sie DFS - post order) ustawiamy na 2 odwiedzoneWezly[wezel] = 2; cout << wezel << " "; // TUTAJ NALEZY WYKONAC OPERACJE NA ELEMENCIE DANEJ SSS } continue; } // przy pierwszym wejsciu do wezla ustawiamy na 1 odwiedzoneWezly[wezel] = 1; // dodajemy ten sam wezel ponownie na stos, zeby odwiedzic go podczas cofania wezlyDoOdwiedzenia.push(wezel); for(int wezelSasiedni : listaSasiadowGrafTransponowany[wezel]) { if(!odwiedzoneWezly[wezelSasiedni]) wezlyDoOdwiedzenia.push(wezelSasiedni); } } cout << endl; // TUTAJ KONCZY SIE SSS idSilnieSkladowej++; } return 0; }
Dla studentów którzy mają zadanie 'od babki’:
Jeśli chodzi o zadanie 'od babki’ to trzeba jeszcze dodać jednego 'for’ (może być z DFSem jak w drugim 'forze’ lub można w drugim 'forze’ wygenerować sobie 'mapę’ ze spisem wszystkich węzłów w każdej SSS) do policzenia ile każda silnie składowa spójna ma sąsiednich SSS, a potem jeszcze jeden 'for’ do wyświetlenia węzłów należących do tej SSS.
Algorytm który udostępniłem zakłada numerowanie węzłów od 0, a nie 1 jak w danych przykładowych od babki, więc należy przy wczytywaniu połączeń między węzłami zawsze zmieniać ’-1′ każde połączenie!