Número de elementos cíclicos en una array donde podemos saltar según el valor

Dada una array arr[] de n enteros. Para cada valor arr[i], podemos movernos a arr[i] + 1 en el sentido de las agujas del reloj 
considerando los elementos del arreglo en ciclo. Necesitamos contar elementos cíclicos en la array. Un elemento es cíclico si a partir de él y moviéndose a arr[i] + 1 conduce al mismo elemento.

Ejemplos:  

Input : arr[] = {1, 1, 1, 1}
Output : 4
All 4 elements are cyclic elements.
1 -> 3 -> 1
2 -> 4 -> 2
3 -> 1 -> 3
4 -> 2 -> 4

Input : arr[] = {3, 0, 0, 0}
Output : 1
There is one cyclic point 1,
1 -> 1
The path covered starting from 2 is
2 -> 3 -> 4 -> 1 -> 1.

The path covered starting from 3 is
2 -> 3 -> 4 -> 1 -> 1.

The path covered starting from 4 is
4 -> 1 -> 1

Una solución simple es verificar todos los elementos uno por uno. Seguimos un camino simple a partir de cada elemento arr[i], vamos a arr[i] + 1. Si volvemos a un elemento visitado que no sea arr[i], no contamos arr[i]. La complejidad temporal de esta solución es O(n 2 )

Una solución eficiente se basa en los siguientes pasos. 

  1. Cree un gráfico dirigido utilizando índices de array como Nodes. Agregamos un borde de i al Node (arr[i] + 1)%n. 
  2. Una vez que se crea un gráfico, encontramos todos los componentes fuertemente conectados usando el Algoritmo de Kosaraju 
  3. Finalmente devolvemos la suma de recuentos de Nodes en componentes individuales fuertemente conectados.

Implementación:

C++

// C++ program to count cyclic points
// in an array using Kosaraju's Algorithm
#include <bits/stdc++.h>
using namespace std;
 
// Most of the code is taken from below link
// https://www.geeksforgeeks.org/strongly-connected-components/
class Graph {
    int V;
    list<int>* adj;
    void fillOrder(int v, bool visited[],
                      stack<int>& Stack);
    int DFSUtil(int v, bool visited[]);
 
public:
    Graph(int V);
    void addEdge(int v, int w);
    int countSCCNodes();
    Graph getTranspose();
};
 
Graph::Graph(int V)
{
    this->V = V;
    adj = new list<int>[V];
}
 
// Counts number of nodes reachable
// from v
int Graph::DFSUtil(int v, bool visited[])
{
    visited[v] = true;
    int ans = 1;
    list<int>::iterator i;
    for (i = adj[v].begin(); i != adj[v].end(); ++i)
        if (!visited[*i])
           ans += DFSUtil(*i, visited);
    return ans;
}
 
Graph Graph::getTranspose()
{
    Graph g(V);
    for (int v = 0; v < V; v++) {
        list<int>::iterator i;
        for (i = adj[v].begin(); i != adj[v].end(); ++i)
            g.adj[*i].push_back(v);
    }
    return g;
}
 
void Graph::addEdge(int v, int w)
{
    adj[v].push_back(w);
}
 
void Graph::fillOrder(int v, bool visited[],
                           stack<int>& Stack)
{
    visited[v] = true;
    list<int>::iterator i;
    for (i = adj[v].begin(); i != adj[v].end(); ++i)
        if (!visited[*i])
            fillOrder(*i, visited, Stack);
    Stack.push(v);
}
 
// This function mainly returns total count of
// nodes in individual SCCs using Kosaraju's
// algorithm.
int Graph::countSCCNodes()
{
    int res = 0;
    stack<int> Stack;
    bool* visited = new bool[V];
    for (int i = 0; i < V; i++)
        visited[i] = false;
    for (int i = 0; i < V; i++)
        if (visited[i] == false)
            fillOrder(i, visited, Stack);
    Graph gr = getTranspose();
    for (int i = 0; i < V; i++)
        visited[i] = false;
    while (Stack.empty() == false) {
        int v = Stack.top();
        Stack.pop();
        if (visited[v] == false) {
            int ans = gr.DFSUtil(v, visited);
            if (ans > 1)
                res += ans;
        }
    }
    return res;
}
 
// Returns count of cyclic elements in arr[]
int countCyclic(int arr[], int n)
{
    int  res = 0;
 
    // Create a graph of array elements
    Graph g(n + 1);
 
    for (int i = 1; i <= n; i++) {
        int x = arr[i-1];
 
        // If i + arr[i-1] jumps beyond last
        // element, we take mod considering
        // cyclic array
        int v = (x + i) % n + 1;
 
        // If there is a self loop, we
        // increment count of cyclic points.
        if (i == v)
            res++;
 
        g.addEdge(i, v);
    }
 
    // Add nodes of strongly connected components
    // of size more than 1.
    res += g.countSCCNodes();
 
    return res;
}
 
// Driver code
int main()
{
    int arr[] = {1, 1, 1, 1};
    int n = sizeof(arr)/sizeof(arr[0]);
    cout << countCyclic(arr, n);
    return 0;
}

Java

// Python3 program to count cyclic points
// in an array using Kosaraju's Algorithm
 
// Counts number of nodes reachable
// from v
import java.io.*;
import java.util.*;
class GFG
{
  static boolean[] visited = new boolean[100];
  static Stack<Integer> stack = new Stack<Integer>();
  static ArrayList<ArrayList<Integer>> adj =
    new ArrayList<ArrayList<Integer>>();
 
  static int DFSUtil(int v)
  {
    visited[v] = true;
    int ans = 1;
    for(int i: adj.get(v))
    {
      if(!visited[i])
      {
        ans += DFSUtil(i);
      }
    }
    return ans;
  }
  static void getTranspose()
  {
 
    for(int v = 0; v < 5; v++)
    {
      for(int i : adj.get(v))
      {
        adj.get(i).add(v);
      }
    }
  }
  static void addEdge(int v, int w)
  {
    adj.get(v).add(w);
  }
  static void fillOrder(int v)
  {
    visited[v] = true;
    for(int i: adj.get(v))
    {
      if(!visited[i])
      {
        fillOrder(i);
      }
    }
    stack.add(v);
  }
 
  // This function mainly returns total count of
  // nodes in individual SCCs using Kosaraju's
  // algorithm.
  static int countSCCNodes()
  {
    int res = 0;
 
    // stack<int> Stack;
    // bool* visited = new bool[V];
    for(int i = 0; i < 5; i++)
    {
      if(visited[i] == false)
      {
        fillOrder(i);
      }
    }
    getTranspose();
    for(int i = 0; i < 5; i++)
    {
      visited[i] = false;
    }
    while(stack.size() > 0)
    {
      int v = stack.get(stack.size() - 1);
      stack.remove(stack.size() - 1);
      if (visited[v] == false)
      {
        int ans = DFSUtil(v);
        if (ans > 1)
        {
          res += ans;
        }
      }
    }
    return res;
  }
 
  // Returns count of cyclic elements in arr[]
  static int countCyclic(int[] arr, int n)
  {
    int res = 0;
 
    // Create a graph of array elements
    for(int i = 1; i < n + 1; i++)
    {
      int x = arr[i - 1];
 
      // If i + arr[i-1] jumps beyond last
      // element, we take mod considering
      // cyclic array
      int v = (x + i) % n + 1;
 
      // If there is a self loop, we
      // increment count of cyclic points.
      if (i == v)
        res++;
      addEdge(i, v);
    }
 
    // Add nodes of strongly connected components
    // of size more than 1.
    res += countSCCNodes();
    return res;
  }
 
  // Driver code
  public static void main (String[] args)
  {
    int arr[] = {1, 1, 1, 1};
    int n = arr.length;
    for(int i = 0; i < 100; i++)
    {
      adj.add(new ArrayList<Integer>());
 
    }
    System.out.println(countCyclic(arr, n));
  }
}
 
// This code is contributed by avanitrachhadiya2155

Python3

# Python3 program to count cyclic points
# in an array using Kosaraju's Algorithm
 
# Counts number of nodes reachable
# from v
def DFSUtil(v):
     
    global visited, adj
 
    visited[v] = True
    ans = 1
 
    for i in adj[v]:
        if (not visited[i]):
           ans += DFSUtil(i)
            
    return ans
 
def getTranspose():
     
    global visited, adj
 
    for v in range(5):
        for i in adj[v]:
            adj[i].append(v)
 
def addEdge(v, w):
     
    global visited, adj
    adj[v].append(w)
 
def fillOrder(v):
     
    global Stack, adj, visited
    visited[v] = True
     
    for i in adj[v]:
        if (not visited[i]):
            fillOrder(i)
             
    Stack.append(v)
 
# This function mainly returns total count of
# nodes in individual SCCs using Kosaraju's
# algorithm.
def countSCCNodes():
     
    global adj, visited, S
    res = 0
     
    #stack<int> Stack;
    #bool* visited = new bool[V];
    for i in range(5):
        if (visited[i] == False):
            fillOrder(i)
             
    getTranspose()
    for i in range(5):
        visited[i] = False
 
    while (len(Stack) > 0):
        v = Stack[-1]
        del Stack[-1]
         
        if (visited[v] == False):
            ans = DFSUtil(v)
            if (ans > 1):
                res += ans
 
    return res
 
# Returns count of cyclic elements in arr[]
def countCyclic(arr, n):
     
    global adj
    res = 0
 
    # Create a graph of array elements
    for i in range(1, n + 1):
        x = arr[i - 1]
 
        # If i + arr[i-1] jumps beyond last
        # element, we take mod considering
        # cyclic array
        v = (x + i) % n + 1
 
        # If there is a self loop, we
        # increment count of cyclic points.
        if (i == v):
            res += 1
 
        addEdge(i, v)
 
    # Add nodes of strongly connected components
    # of size more than 1.
    res += countSCCNodes()
 
    return res
 
# Driver code
if __name__ == '__main__':
     
    adj = [[] for i in range(100)]
    visited = [False for i in range(100)]
    arr = [ 1, 1, 1, 1 ]
    Stack = []
    n = len(arr)
     
    print(countCyclic(arr, n))
 
# This code is contributed by mohit kumar 29

C#

// C# program to count cyclic points
// in an array using Kosaraju's Algorithm
 
// Counts number of nodes reachable
// from v
using System;
using System.Collections.Generic;
public class GFG
{
 
  static bool[] visited = new bool[100];
  static List<int> stack = new List<int>();
  static List<List<int>> adj = new List<List<int>>();
  static int DFSUtil(int v)
  {
    visited[v] = true;
    int ans = 1;
    foreach(int i in adj[v])
    {
      if(!visited[i])
      {
        ans += DFSUtil(i);
      }
    }
    return ans;
  }
  static void getTranspose()
  {
    for(int v = 0; v < 5; v++)
    {
      foreach(int i in adj[v])
      {
        adj[i].Add(v);
      }
    }
  }
  static void addEdge(int v, int w)
  {
    adj[v].Add(w);
  }
  static void fillOrder(int v)
  {
    visited[v] = true;
    foreach(int i in adj[v])
    {
      if(!visited[i])
      {
        fillOrder(i);
      }
    }
    stack.Add(v);
  }
 
  // This function mainly returns total count of
  // nodes in individual SCCs using Kosaraju's
  // algorithm.
  static int countSCCNodes()
  {
    int res = 0;
 
    // stack<int> Stack;
    // bool* visited = new bool[V];
    for(int i = 0; i < 5; i++)
    {
      if(visited[i] == false)
      {
        fillOrder(i);
      }
    }
    getTranspose();
    for(int i = 0; i < 5; i++)
    {
      visited[i] = false;
    }
    while(stack.Count > 0)
    {
      int v=stack[stack.Count - 1];
      stack.Remove(stack.Count - 1);
      if (visited[v] == false)
      {
        int ans = DFSUtil(v);
        if (ans > 1)
        {
          res += ans;
        }
      }
    }
    return res;
  }
 
  // Returns count of cyclic elements in arr[]
  static int countCyclic(int[] arr, int n)
  {
    int res = 0;
 
    // Create a graph of array elements
    for(int i = 1; i < n + 1; i++)
    {
      int x = arr[i - 1];
 
      // If i + arr[i-1] jumps beyond last
      // element, we take mod considering
      //cyclic array
      int v = (x + i) % n + 1;   
 
      // If there is a self loop, we
      // increment count of cyclic points.
      if (i == v)
        res++;
      addEdge(i, v);
    }
 
    // Add nodes of strongly connected components
    // of size more than 1.
    res += countSCCNodes();
    return res;
  }
 
  // Driver code
  static public void Main ()
  {
    int[] arr = {1, 1, 1, 1};
    int n = arr.Length;
    for(int i = 0; i < 100; i++)
    {
      adj.Add(new List<int>());
    }
    Console.WriteLine(countCyclic(arr, n));
  }
}
 
// This code is contributed by rag2127

Javascript

<script>
// Javascript program to count cyclic points
// in an array using Kosaraju's Algorithm
  
// Counts number of nodes reachable
// from v
     
    let visited = new Array(100);
    for(let i=0;i<100;i++)
    {
        visited[i]=false;
    }
    let stack = [];
    let adj=[];
     
function DFSUtil(v)
{
    visited[v] = true;
    let ans = 1;
    for(let i=0;i<adj[v].length;i++)
    {
      if(!visited[adj[v][i]])
      {
        ans += DFSUtil(adj[v][i]);
      }
    }
    return ans;
}
 
function getTranspose()
{
    for(let v = 0; v < 5; v++)
    {
      for(let i=0;i<adj[v].length;i++)
      {
        adj[adj[v][i]].push(v);
      }
    }
}
 
function addEdge(v,w)
{
    adj[v].push(w);
}
 
function fillOrder(v)
{
    visited[v] = true;
    for(let i=0;i<adj[v].length;i++)
    {
      if(!visited[adj[v][i]])
      {
        fillOrder(adj[v][i]);
      }
    }
    stack.push(v);
}
 
// This function mainly returns total count of
  // nodes in individual SCCs using Kosaraju's
  // algorithm.
function countSCCNodes()
{
let res = 0;
  
    // stack<int> Stack;
    // bool* visited = new bool[V];
    for(let i = 0; i < 5; i++)
    {
      if(visited[i] == false)
      {
        fillOrder(i);
      }
    }
    getTranspose();
    for(let i = 0; i < 5; i++)
    {
      visited[i] = false;
    }
    while(stack.length > 0)
    {
      let v = stack[stack.length - 1];
      stack.pop();
      if (visited[v] == false)
      {
        let ans = DFSUtil(v);
        if (ans > 1)
        {
          res += ans;
        }
      }
    }
    return res;
}
 
// Returns count of cyclic elements in arr[]
function countCyclic(arr,n)
{
    let res = 0;
  
    // Create a graph of array elements
    for(let i = 1; i < n + 1; i++)
    {
      let x = arr[i - 1];
  
      // If i + arr[i-1] jumps beyond last
      // element, we take mod considering
      // cyclic array
      let v = (x + i) % n + 1;
  
      // If there is a self loop, we
      // increment count of cyclic points.
      if (i == v)
        res++;
      addEdge(i, v);
    }
  
    // Add nodes of strongly connected components
    // of size more than 1.
    res += countSCCNodes();
    return res;
}
 
// Driver code
let arr=[1, 1, 1, 1];
let n = arr.length;
for(let i = 0; i < 100; i++)
{
    adj.push([]);
 
}
document.write(countCyclic(arr, n));
     
     
 
// This code is contributed by unknown2108
</script>
Producción

4

Complejidad de tiempo: O(n) 
Espacio auxiliar: O(n) Tenga en cuenta que solo hay O(n) aristas.

Este artículo es una contribución de Mohak Agrawal . Si te gusta GeeksforGeeks y te gustaría contribuir, también puedes escribir un artículo usando write.geeksforgeeks.org o enviar tu artículo por correo a review-team@geeksforgeeks.org. Vea su artículo que aparece en la página principal de GeeksforGeeks y ayude a otros Geeks. 

Publicación traducida automáticamente

Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *