static Grafo_Dir MontagemGrafoDir(string arqName)
        {
            Grafo_Dir grafo;

            StreamReader       reader    = new StreamReader(arqName);
            int                nVertices = int.Parse(reader.ReadLine());
            List <ParOrdenado> lista     = new List <ParOrdenado>();

            while (!reader.EndOfStream)
            {
                int      x, y, peso, direcao;
                string   linha    = reader.ReadLine();
                string[] vetSplit = linha.Split(';');
                x       = int.Parse(vetSplit[0]) - 1;
                y       = int.Parse(vetSplit[1]) - 1;
                peso    = int.Parse(vetSplit[2]);
                direcao = int.Parse(vetSplit[3]);
                if (direcao == -1)
                {
                    int aux = x;
                    x = y;
                    y = aux;
                }
                ParOrdenado par = new ParOrdenado(x, y, peso);
                lista.Add(par);
            }

            reader.Close();

            return(grafo = new Grafo_Dir(nVertices, lista));
        }
        public Grafo_Dir Kruskal()
        {
            //algoritmo só deve ser executado em grafos conexos
            if (!isConexo()) //se o grafo não é conexo, o algoritmo não será executado e retornará null
            {
                return(null);
            }

            //pré processamento dos dados
            List <Aresta>      listaArestas = new List <Aresta>();
            List <ParOrdenado> pares        = new List <ParOrdenado>();
            Grafo_Dir          grafoAuxilir = new Grafo_Dir(Vertices.Length, pares);

            for (int g = 0; g < Vertices.Length; g++)
            {
                for (int a = 0; a < Vertices[g].ListaDeAdjacencia.Count; a++)
                {
                    if (Vertices[g].ListaDeAdjacencia[a].Direcao == 1)
                    {
                        listaArestas.Add(Vertices[g].ListaDeAdjacencia[a]);
                    }
                }
            }

            Aresta[] arestasOrdenadas = insertionSort(listaArestas.ToArray());
            //dados processados e arestas já ordenadas

            //para cada aresta no vetor de aresta
            for (int v = 0; v < arestasOrdenadas.Length; v++)
            {
                //capturar origem e destino da aresta, ignorando a direção, pois é um grafo não dirigido
                int idOrigem  = arestasOrdenadas[v].verticeOrigem.ID;
                int idDestino = arestasOrdenadas[v].verticeDestino.ID;

                //if para ignorar os loops do grafo original
                if (idOrigem != idDestino)
                {
                    //fila auxiliar para executar a busca pelo ciclo
                    Queue <int> fila = new Queue <int>();

                    //verifica se a adição da nova aresta vai gerar um ciclo
                    if (!VerificarCiclo(fila, idOrigem, idDestino, idDestino, grafoAuxilir))
                    {
                        grafoAuxilir.FormarNovaAresta(idOrigem, idDestino, arestasOrdenadas[v].Peso); //não formando ciclo, nova aresta é criada
                    }
                }
            }

            return(grafoAuxilir);
        }
        private bool VerificarCiclo(Queue <int> fila, int idOrigem, int idDestino, int idAtual, Grafo_Dir grafoAux)
        {
            //MÉTODO RECURSIVO BASEADO NA TRAVESSIA EM AMPLITUDE
            grafoAux.Vertices[idAtual].EstadoCor = 2;

            //para cada item da lista de adjacencia do vértice atual
            for (int w = 0; w < grafoAux.Vertices[idAtual].ListaDeAdjacencia.Count; w++)
            {
                //se a direção é origem -> destino
                if (grafoAux.Vertices[idAtual].ListaDeAdjacencia[w].Direcao == 1)
                {
                    //captura o indice do vertice destino
                    int idLaco = grafoAux.Vertices[idAtual].ListaDeAdjacencia[w].verticeDestino.ID;

                    //se o indice capturado for igual a origem, singnifica que esses componentes ja são conexos
                    //a adição de uma nova aresta, formaria um ciclo, portanto, retorna verdadeiro
                    if (idLaco == idOrigem)
                    {
                        //reseta as cores do grafo auxiliar, para não atrapalhar as próximas execuções do algoritmo
                        grafoAux.ResetarCores();
                        return(true);
                    }

                    else
                    {
                        //verifica se o vertice já não foi visitado anteriormente
                        if (grafoAux.Vertices[idLaco].EstadoCor == 1)
                        {
                            fila.Enqueue(idLaco);                    //enfileira o indice do vertice que está sendo visitado
                            grafoAux.Vertices[idLaco].EstadoCor = 2; //pinta o vertice de azul
                        }
                    }
                }
            }

            grafoAux.Vertices[idAtual].EstadoCor = 3; //pinta o vertice de vermelho

            //condição para chamada recursiva
            //se existem itens na fila, ainda há vertices para verificar a condição de ciclo
            if (fila.Count > 0)
            {
                //remove da fila, detectando o próximo vertice a ser verificado
                int prox = fila.Dequeue();

                //chamada recursiva com parametros atualizados
                return(VerificarCiclo(fila, idOrigem, idDestino, prox, grafoAux));
            }

            //else que será executado quando todos os vértices já tiverem sido visitados
            else
            {
                //reseta as cores do grafo auxiliar, para não atrapalhar as próximas execuções do algoritmo
                grafoAux.ResetarCores();
                return(false);
            }
        }