E045. Проверка grapheа на ацикличность и нахождение цикла
Источник: e-maxx.ru/algo, страница PDF 137.
Пусть дан ориентированный или неориентированный graphe без петель и кратных рёбер. it is required проверить, является ли он ациклическим, а если не является, то find любой цикл. Решим эту задачу с помощью поиска в глубину за O (M).
Algorithme
Произведём серию поисков в глубину в grapheе. Т.е. из каждой вершины, в которую мы ещё ни разу не приходили, запустим Depth-first search, который при Entréeе в вершину будет красить её в серый цвет, а при Sortieе - в чёрный. И если Depth-first search пытается пойти в серую вершину, то это означает, что мы нашли цикл (если graphe неориентированный, то случаи, когда Depth-first search из какой-то вершины пытается пойти в предка, не считаются). Сам цикл можно восстановить проходом по tableauу предков.
Implémentation
Здесь приведена Implémentation для случая ориентированного grapheа.
int n;
vector < vector<int> > g;
vector<char> cl;
vector<int> p;
int cycle_st, cycle_end;
bool dfs (int v) {
cl[v] = 1;
for (size_t i=0; i<g[v].size(); ++i) {
int to = g[v][i];
if (cl[to] == 0) {
p[to] = v;
if (dfs (to)) return true;
}
else if (cl[to] == 1) {
cycle_end = v;
cycle_st = to;
return true;
} }
cl[v] = 2;
return false;
}
int main() {
... чтение grapheа ...
p.assign (n, -1);
cl.assign (n, 0);
cycle_st = -1;
for (int i=0; i<n; ++i)
if (dfs (i))
break;
if (cycle_st == -1)
puts ("Acyclic");
else {
puts ("Cyclic");
vector<int> cycle;
cycle.push_back (cycle_st);
for (int v=cycle_end; v!=cycle_st; v=p[v])
cycle.push_back (v);
cycle.push_back (cycle_st);
reverse (cycle.begin(), cycle.end());
for (size_t i=0; i<cycle.size(); ++i)
printf ("%d ", cycle[i]+1);
} }
C# solution
brouillon automatique, à relire avant soumissionusing System;
using System.Collections.Generic;
using System.Linq;
public static class AlgorithmDraft
{
// Auto-generated C# draft from the original e-maxx C/C++ listing. Review before production use.
int n;
vector < List<int> > g;
List<char> cl;
List<int> p;
int cycle_st, cycle_end;
bool dfs (int v) {
cl[v] = 1;
for (size_t i=0; i<g[v].size(); ++i) {
int to = g[v][i];
if (cl[to] == 0) {
p[to] = v;
if (dfs (to)) return true;
}
else if (cl[to] == 1) {
cycle_end = v;
cycle_st = to;
return true;
}
}
cl[v] = 2;
return false;
}
int main() {
... чтение графа ...
p.assign (n, -1);
cl.assign (n, 0);
cycle_st = -1;
for (int i=0; i<n; ++i)
if (dfs (i))
break;
if (cycle_st == -1)
puts ("Acyclic");
else {
puts ("Cyclic");
List<int> cycle;
cycle.push_back (cycle_st);
for (int v=cycle_end; v!=cycle_st; v=p[v])
cycle.push_back (v);
cycle.push_back (cycle_st);
reverse (cycle.begin(), cycle.end());
for (size_t i=0; i<cycle.size(); ++i)
Console.Write ("%d ", cycle[i]+1);
}
}
}
C++ solution
correspondant/originalint n;
vector < vector<int> > g;
vector<char> cl;
vector<int> p;
int cycle_st, cycle_end;
bool dfs (int v) {
cl[v] = 1;
for (size_t i=0; i<g[v].size(); ++i) {
int to = g[v][i];
if (cl[to] == 0) {
p[to] = v;
if (dfs (to)) return true;
}
else if (cl[to] == 1) {
cycle_end = v;
cycle_st = to;
return true;
}
}
cl[v] = 2;
return false;
}
int main() {
... чтение графа ...
p.assign (n, -1);
cl.assign (n, 0);
cycle_st = -1;
for (int i=0; i<n; ++i)
if (dfs (i))
break;
if (cycle_st == -1)
puts ("Acyclic");
else {
puts ("Cyclic");
vector<int> cycle;
cycle.push_back (cycle_st);
for (int v=cycle_end; v!=cycle_st; v=p[v])
cycle.push_back (v);
cycle.push_back (cycle_st);
reverse (cycle.begin(), cycle.end());
for (size_t i=0; i<cycle.size(); ++i)
printf ("%d ", cycle[i]+1);
}
}
Java solution
brouillon automatique, à relire avant soumissionimport java.util.*;
import java.math.*;
public class AlgorithmDraft {
// Auto-generated Java draft from the original e-maxx C/C++ listing. Review before production use.
int n;
vector < ArrayList<Integer> > g;
ArrayList<Character> cl;
ArrayList<Integer> p;
int cycle_st, cycle_end;
boolean dfs (int v) {
cl[v] = 1;
for (size_t i=0; i<g[v].size(); ++i) {
int to = g[v][i];
if (cl[to] == 0) {
p[to] = v;
if (dfs (to)) return true;
}
else if (cl[to] == 1) {
cycle_end = v;
cycle_st = to;
return true;
}
}
cl[v] = 2;
return false;
}
int main() {
... чтение графа ...
p.assign (n, -1);
cl.assign (n, 0);
cycle_st = -1;
for (int i=0; i<n; ++i)
if (dfs (i))
break;
if (cycle_st == -1)
puts ("Acyclic");
else {
puts ("Cyclic");
ArrayList<Integer> cycle;
cycle.push_back (cycle_st);
for (int v=cycle_end; v!=cycle_st; v=p[v])
cycle.push_back (v);
cycle.push_back (cycle_st);
reverse (cycle.begin(), cycle.end());
for (size_t i=0; i<cycle.size(); ++i)
System.out.print ("%d ", cycle[i]+1);
}
}
}
Материал разбит как Algorithmeическая Problème: изучить постановку, понять асимптотику и реализовать Algorithme на выбранном языке.
Vacancies for this task
offres actives with overlapping task tags are affichés.