Ciclos são caminhos fechados quase simples de comprimento pelo menos 2. Em grafos, os ciclos de comprimento 2 não são considerados "válidos".
Ciclos
Um ciclo (= cycle) num digrafo é um caminho fechado de comprimento pelo menos 2, sem vértices repetidos, exceto o último (que coincide com o primeiro).
Dizemos que um arco v-w pertence a um dado ciclo se o vértice w é o sucessor de v no ciclo. Todos os arcos de um ciclo apontam no mesmo sentido, de um vértice do ciclo para o seu sucessor. Há quem goste de enfatizar esse fato dizendo "ciclo dirigido" em lugar do nosso "ciclo".
No digrafo 0-1 0-5 1-0 1-5 2-4 3-1 5-3, os caminhos
a) 1-5-3-1
b) 0-1-0
são ciclos. Já os caminhos abaixo, embora fechados, não são ciclos:
a) 1-5-3-1-0-1
b) 1
Ciclos em grafos
Um ciclo é trivial se tem comprimento 2. Num grafo, ciclos triviais são ignorados, pois usam os dois arcos de uma mesma aresta.
Procurando ciclos: primeiro algoritmo
A seguinte função implementa uma maneira óbvia mas pouco eficiente de encontrar um ciclo num digrafo. A idéia é procurar, para cada arco v-w, um ciclo que passe por v-w.
O algoritmo abaixo tem por base a seguinte observação: em relação a qualquer floresta de busca em profundidade:
todo arco de retorno pertence a um ciclo e todo ciclo tem um arco de retorno. Função para Digrafos:
Exercícios para Fixação
1. Escreva uma função que conte o número de ciclos em um grafo.
2. Escreva o algoritmo eficiente para digrafos usando lista de adjacências.
3. Escreva o algoritmo eficiente para grafos usando lista de adjacências.
4. Execute o algoritmo cicloDigrafo eficiente e marque os principais passos para o digrafo da figura:
5. Execute o algoritmo cicloGrafo eficiente e marque os principais passos para o grafo da figura:
6. Escreva a função removeAresta para lista de adjacências
7. Escreva a função insereAresta para lista de adjacências
Referência: IME
Ciclos
Um ciclo (= cycle) num digrafo é um caminho fechado de comprimento pelo menos 2, sem vértices repetidos, exceto o último (que coincide com o primeiro).
Dizemos que um arco v-w pertence a um dado ciclo se o vértice w é o sucessor de v no ciclo. Todos os arcos de um ciclo apontam no mesmo sentido, de um vértice do ciclo para o seu sucessor. Há quem goste de enfatizar esse fato dizendo "ciclo dirigido" em lugar do nosso "ciclo".
No digrafo 0-1 0-5 1-0 1-5 2-4 3-1 5-3, os caminhos
a) 1-5-3-1
b) 0-1-0
são ciclos. Já os caminhos abaixo, embora fechados, não são ciclos:
a) 1-5-3-1-0-1
b) 1
Ciclos em grafos
Um ciclo é trivial se tem comprimento 2. Num grafo, ciclos triviais são ignorados, pois usam os dois arcos de uma mesma aresta.
Procurando ciclos: primeiro algoritmo
A seguinte função implementa uma maneira óbvia mas pouco eficiente de encontrar um ciclo num digrafo. A idéia é procurar, para cada arco v-w, um ciclo que passe por v-w.
//Devolve 1 se tem ciclo no digrafo G, devolve 0 caso contrário.
int G[MAXV][MAXV];//G está representando um grafo por matriz de adjancências
int n; //n é o número total de vértices (que são números de 0 a N-1)
int cicloDigrafo(){
int v, dest, saida;
for( v = 0 ; v < n ; ++v ){
for( dest = 0 ; dest < n ; ++dest ){
if( G[v][dest] == 1 && Path(dest,v)){
return 1;
}
}
}
return 0;
}A função Path no código acima está implementada no artigo de caminhos em digrafos. A função análoga para grafos é bem mais complexa porque é preciso evitar os ciclos triviais. int G[MAXV][MAXV];//G está representando um grafo por matriz de adjancências
int n; //n é o número total de vértices (que são números de 0 a N-1)
//A função a seguir remove uma Aresta
void removeAresta(int o,int d){
G[o][d] = 0;
}
//A função a seguir insere uma Aresta
void insereAresta(int o,int d){
G[o][d] = 1;
}
//A função a seguir devolve 1 se existe um ciclo não-trivial no grafo G, caso contrário devolve 0.
int cicloGrafo(){
int v, w;
int dest;
int saida;
for( v = 0 ; v < n ; ++v ){
for( dest = 0 ; dest < n ; ++dest ){
if( G[v][dest] == 1 ){
if ( v < dest ){
removeAresta(dest,v);
saida = Path(dest,v);
insereAresta(dest,v);
if(saida == 1)
return 1;
}
}
}
}
return 0;
}Procurando ciclos: algoritmo eficiente A estratégia da busca em profundidade permite encontrar ciclos de maneira muito eficiente. O algoritmo abaixo tem por base a seguinte observação: em relação a qualquer floresta de busca em profundidade:
todo arco de retorno pertence a um ciclo e todo ciclo tem um arco de retorno. Função para Digrafos:
#define MAXV 100 //número máximo de vértices
int G[MAXV][MAXV]; //grafo representado por matriz de adjacência
int ordemvisit[MAXV]; //marca a ordem de visitação dos vértices
int n; //número de vértices neste grafo
int count; //contador
//A função abaixo devolve 1 se o digrafo G tem um ciclo, 0 caso contrário
int cicloDigrafo(){
int v;
for( v = 0 ; v < n ; ++ v )
ordemvisit[v] = -1;
count = 0;
for( v = 0 ; v < n ; ++ v )
if( ordemvisit[v] == -1 )
if(cicloR(v) == 1)
return 1;
return 0;
}
//A função abaixo devolve 1 quando encontra um ciclo ao percorrer G a partir de v
int cicloR(int v){
int p;
ordemvisit[v] = count++;
for( p = 0 ; p < n ; ++p ){
if(G[v][p] == 1 && ordemvisit[p] == -1){
if(cicloR(p) == 1) return 1;
}
else if(ordemvisit[p] < ordemvisit[v]) return 1;
}
return 0;
}A função cicloGrafo abaixo procura ciclos não-triviais em grafos. Para evitar ciclos triviais, a função precisa ter acesso à floresta DFS. #define MAXV 100 //número máximo de vértices
int G[MAXV][MAXV]; //grafo representado por matriz de adjacência
int ordemvisit[MAXV]; //marca a ordem de visitação dos vértices
int pai[MAXV]; //vetor de pai, pai de X é pai[X]
int n; //número de vértices neste grafo
int count; //contador
//A função abaixo devolve 1 se o grafo G tem um ciclo não-trivial, 0 caso contrário
int cicloGrafo(){
int v;
for( v = 0 ; v < n ; ++ v )
ordemvisit[v] = -1;
count = 0;
for( v = 0 ; v < n ; ++ v ){
if( ordemvisit[v] == -1 ){
pai[v] = v;
if(ciclo3R(v) == 1)
return 1;
}
}
return 0;
}
//A função abaixo devolve 1 quando encontra um ciclo não-trivial ao percorrer G a partir de v
int cicloR(int v){
int p;
ordemvisit[v] = count++;
for( p = 0 ; p < n ; ++p ){
if(G[v][p] == 1 && ordemvisit[p] == -1){
pai[p] = p;
if(cicloR(p) == 1) return 1;
}
else if(ordemvisit[p] < ordemvisit[v] && p != pai[v])
return 1;
}
return 0;
}Exercícios para Fixação
1. Escreva uma função que conte o número de ciclos em um grafo.
2. Escreva o algoritmo eficiente para digrafos usando lista de adjacências.
3. Escreva o algoritmo eficiente para grafos usando lista de adjacências.
4. Execute o algoritmo cicloDigrafo eficiente e marque os principais passos para o digrafo da figura:
5. Execute o algoritmo cicloGrafo eficiente e marque os principais passos para o grafo da figura:
6. Escreva a função removeAresta para lista de adjacências
7. Escreva a função insereAresta para lista de adjacências
Referência: IME
Parabens pela explicação, muito util.
@Paulo, muito obrigado, volte sempre!
Muito obrigado por sua explicação, com ela consegui enxergar um bom modo de reconhecer ciclos!