Otkrivanje ciklusa u usmerenim grafovima
Kod usmerenih grafova (DAG ili ne-DAG) često je potrebno utvrditi da li graf sadrži ciklus pre nego što primenimo algoritme kao što su topološko sortiranje, najduži put u DAG-u, kritični put itd.
Ako graf sadrži ciklus, tada nije DAG i mnogi algoritmi neće raditi ispravno.
Šta je ciklus?
Ciklus je niz čvorova (v1, v2, ..., vk) takav da postoji put od
vi → v(i+1) za sve i, i dodatno vk → v1.
Najkraći oblik ciklusa je jednostavno:
A → B → A
A → B
↑ ↓
D ← C
Ovaj graf očigledno ima ciklus.
Metoda 1: DFS + obeležavanje stanja
Koristimo 3 vrste obeležavanja čvorova:
- 0 → nije posećen
- 1 → u toku obilaska (trenutno u rekurzivnom steku)
- 2 → potpuno obrađen
Ako tokom DFS-a dođemo do čvora koji je već 1 → pronašli smo ciklus!
#include <bits/stdc++.h>
using namespace std;
vector<vector<int>> g;
vector<int> state;
bool ciklus = false;
void dfs(int u){
state[u] = 1; // trenutno posećen
for(int v : g[u]){
if(state[v] == 0) dfs(v);
else if(state[v] == 1) ciklus = true; // povratna grana → ciklus!
}
state[u] = 2; // obrađen
}
int main(){
int n, m;
cin >> n >> m;
g.resize(n);
state.assign(n, 0);
for(int i=0;i<m;i++){
int a, b;
cin >> a >> b;
g[a].push_back(b);
}
for(int i=0;i<n;i++)
if(state[i] == 0) dfs(i);
if(ciklus) cout << "DA, graf sadrzi ciklus!";
else cout << "NE, graf je DAG.";
}
Metoda 2: Kahn-ov algoritam i stepen ulaza
Ideja:
- Brojimo koliko grana ulazi u svaki čvor
- Čvorovi sa ulaznim stepenom = 0 se uklanjaju (kao u topološkom sortiranju)
- Ako smo uspeli ukloniti sve čvorove → nema ciklusa
- Ako broj izbačenih čvorova < broj čvorova → postoji ciklus!
#include <bits/stdc++.h>
using namespace std;
int main(){
int n, m;
cin >> n >> m;
vector<vector<int>> g(n);
vector<int> indeg(n,0);
for(int i=0;i<m;i++){
int a,b;
cin >> a >> b;
g[a].push_back(b);
indeg[b]++;
}
queue<int> q;
for(int i=0;i<n;i++)
if(indeg[i] == 0) q.push(i);
int count_removed = 0;
while(!q.empty()){
int u = q.front(); q.pop();
count_removed++;
for(int v : g[u]){
indeg[v]--;
if(indeg[v] == 0) q.push(v);
}
}
if(count_removed == n)
cout << "Graf je DAG (nema ciklusa)";
else
cout << "Graf sadrzi ciklus!";
}
Primer (ASCII graf sa ciklusom)
0 → 1 → 2
↑ ↓
└───────3
Po DFS metodi: ruta 3 → 0 → 1 → 2 → 3 otkriva ciklus.
Po Kahn-ovoj metodi: nijedan čvor nema stepen ulaza = 0 → odmah znamo da postoji ciklus.
Koju metodu koristiti?
| Metoda | Prednosti | Nedostaci |
|---|---|---|
| DFS | Brza, jednostavna, radi i na delimičnim grafovima | Teže razumljiva početnicima (stanja čvorova) |
| Kahn (BFS) | Odmah daje i topološki redosled | Radi samo na usmerenim grafovima |
Zadaci za vežbu
- Uneti graf i proveriti da li je DAG (oba pristupa)
- Pronaći čvorove koji učestvuju u ciklusu (izmeniti DFS)
- Napisati algoritam koji ispisuje jedan ciklus (ako postoji)
- Koristiti Kahn-ov algoritam da proverite graf pre topološkog sortiranja
Zaključak
Detekcija ciklusa je ključni korak u radu sa usmerenim grafovima i dopunjuje lekcije o topološkom sortiranju i dinamičkom programiranju na grafovima.
□ Sledeća preporučena lekcija:
Najduži put u DAG-u (DP + Topološki poredak)