public Automato criaEquivalenteMinimizado() {
        EstadoImpl.reiniciarChave();
        // elimina todos os estados inatingiveis
        this.retiraEstadosInatingiveis();

        List<List<Estado>> conjuntoMinimizavel = null;
        List<List<Estado>> resultadoParcial;// cria S0 com dois conjuntos : nao-finais e finais
        resultadoParcial = new ArrayList<List<Estado>>();
        List<Estado> estadosNaoFinais = new ArrayList<Estado>(this.estados);
        estadosNaoFinais.removeAll(this.estadosFinais);
        resultadoParcial.add(estadosNaoFinais);
        resultadoParcial.add(this.estadosFinais);

        int contadorIteracoes = 0;
        while (!resultadoParcial.equals(conjuntoMinimizavel)) {
            conjuntoMinimizavel = new ArrayList<List<Estado>>(resultadoParcial);
            imprimeConjuntoMinimizavel(conjuntoMinimizavel, contadorIteracoes);
            resultadoParcial.clear();

            // para cada conjunto A de Sn faça
            for (List<Estado> conjunto : conjuntoMinimizavel) {
                List<Estado> subConjunto = new ArrayList<Estado>(conjunto);
                // repita ate C = {}
                // se o conjunto tem mais de um estado então, enquanto o conjunto tiver mais de um estado
                while (subConjunto.size() > 0) {
                    // escolha e de C
                    Estado estadoEscolhido = subConjunto.iterator().next();
                    // Y = {e}
                    // coloque e no agrupamento novo de estados
                    List<Estado> estadosAgrupados = new ArrayList<Estado>();
                    estadosAgrupados.add(estadoEscolhido);
                    // para cada d de C - {e}
                    List<Estado> estadosRestantesConj = new ArrayList<Estado>(subConjunto);
                    estadosRestantesConj.remove(estadoEscolhido);
                    for (Estado estadoD : estadosRestantesConj) {
                        boolean agrupa = true;
                        for (Simbolo simbolo : this.alfabeto) {
                            // verifique se e vai para o mesmo conjunto dos outros do mesmo estado
                            Estado estadoAtingidoPorEscolhido = this.aplicaFuncaoTransicao(estadoEscolhido, simbolo);
                            Estado estadoAtingidoPorD = this.aplicaFuncaoTransicao(estadoD, simbolo);
                            if (isEstadosConjuntosDiferentes(conjuntoMinimizavel, estadoAtingidoPorEscolhido, estadoAtingidoPorD)) {
                                // senao, deve fazer parte de outro conjunto novo
                                agrupa = false;
                                break;
                            }
                        }
                        if (agrupa) {
                            // Y = Y U {d}
                            estadosAgrupados.add(estadoD);
                        }
                    }
                    // C = C - Y
                    subConjunto.removeAll(estadosAgrupados);

                    // R = R U {Y}
                    List<Estado> conjuntoAgrupado = new ArrayList<Estado>();
                    conjuntoAgrupado.addAll(estadosAgrupados);
                    resultadoParcial.add(conjuntoAgrupado);
                }
            }
            ++contadorIteracoes;
        }
        imprimeConjuntoMinimizavel(conjuntoMinimizavel, contadorIteracoes);

        List<Estado> estadosSaida = criaEstadosDeConjuntos(conjuntoMinimizavel);
        List<Estado> estadosFinaisSaida = extraiEstadosFinaisDeEstados(estadosSaida);
        Map<Transicao, Estado> funcoesTransicaoSaida = extraiTransicoes(estadosSaida);

        Automato automatoSaida = new AutomatoImpl();
        automatoSaida.setAlfabeto(this.alfabeto);
        // E' = S
        automatoSaida.setEstados(estadosSaida);
        // i' = conjunto em S que contém i
        Estado novoEstadoInicial = this.extraiEstadoInicialDeEstados(estadosSaida, this.estadoInicial);
        automatoSaida.setEstadoInicial(novoEstadoInicial);
        // F' = {C E S|C conj-prop F}
        automatoSaida.setEstadosFinais(estadosFinaisSaida);
        // ft' : para todos C E S e E Alfabeto :
        // ft'(C, a) = conjunto em S que contém ft(e, a) para algum e E C
        automatoSaida.setFuncoesTransicao(funcoesTransicaoSaida);

        return automatoSaida;
    }