Ejemplo n.º 1
0
def busca_largura_lexicografica(G):
    lista_vertices = ListaDuplamenteEncadeada()
    pos_vertices = {}

    for v in G.vertices:  #O(n)
        lista_vertices.inserir_fim(v)  #O(1)
        pos_vertices[v] = lista_vertices.cauda  #O(1)

    Q = ListaDuplamenteEncadeada([Conjunto(lista_vertices, pos_vertices)])

    localizacao = {v: Q.cabeca.prox for v in G.vertices}  #(O(n))
    ordem_eliminacao_perfeita = []  #O(1)
    predecessores = {v: [] for v in G.vertices}  #O(n)
    esta_na_oep = {v: False for v in G.vertices}  #O(n)

    for i in range(len(G.vertices) - 1, -1, -1):
        v = Q.get_primeiro_no().item.vertices.remover_primeiro_no(
        )  #O(1), sempre temos a referência do primeiro conjunto
        del Q.get_primeiro_no().item.pos[
            v.item]  #O(1), remoção de elemento de um dicionário
        if Q.get_primeiro_no().item.vertices.vazia(
        ):  #O(1), ListaDuplamenteEncadeada tem um membro que indica se a lista está vazia ou não
            Q.remover_primeiro_no()  #O(1)
        ordem_eliminacao_perfeita.append(v.item)  #O(1)
        esta_na_oep[v.item] = True  #O(1)
        for u in G.vizinhos[v.item]:  #O(N(u))
            if not esta_na_oep[u]:  #O(1)
                predecessores[u].append(v.item)  #O(1)

        del localizacao[v.item]  #O(1)

        for w in G.vizinhos[v.item]:  #O(N(v))
            try:
                conj_w = localizacao[w]  #O(1)
            except:
                continue
            ant_conj_w = conj_w.ant
            if ant_conj_w == Q.cabeca or ant_conj_w.item.label == "" or ant_conj_w.item.label[
                    -1] != chr(
                        i
                    ):  #O(1), só comparamos 1 char da label ou comparamos com string vazia
                ant_conj_w = No(
                    Conjunto(vertices=ListaDuplamenteEncadeada(),
                             pos={},
                             label=conj_w.item.label + chr(i))
                )  #linear no tamanho da string, que normalmente é negligível :)
                Q.inserir_no_antecessor(ant_conj_w, conj_w)  #O(1)

            no_w = conj_w.item.pos[w]  #O(1)
            conj_w.item.vertices.remover_no(conj_w.item.pos[w])  #O(1)
            del conj_w.item.pos[w]  #O(1)
            if conj_w.item.vertices.vazia():  #O(1)
                Q.remover_no(conj_w)  #O(1)

            localizacao[w] = ant_conj_w
            ant_conj_w.item.vertices.inserir_fim(no_w)
            ant_conj_w.item.pos[w] = no_w
            conta_memoria()

    return (ordem_eliminacao_perfeita, predecessores)
Ejemplo n.º 2
0
def caminho_de_u_ate_v(G, u, v, caminho_proibido=[]):
    fila = deque()
    fila.append(u)
    pred = {u: None}
    caminho_encontrado = False
    while fila:
        w = fila.popleft()
        for x in G.vizinhos[w]:
            if x not in caminho_proibido:
                pred_x = pred.get(x, None)
                if pred_x is None:
                    pred[x] = w
                    fila.append(x)
                    if x == v:
                        conta_memoria()
                        fila.clear()
                        caminho_encontrado = True
                        break

    caminho_uv = []

    if not caminho_encontrado:
        return []

    x = v
    while pred[x] != u:
        caminho_uv.append(pred[x])
        x = pred[x]
    conta_memoria()
    return caminho_uv
Ejemplo n.º 3
0
def eh_cordal_LEXBFS(G):
    OEP, OEP_predecessores = busca_largura_lexicografica(
        G)  #OEP = Ordem de Eliminação Perfeita
    eh_cordal, corda_faltando = testar_ordem_eliminacao_perfeita(
        G, OEP, OEP_predecessores)

    if not eh_cordal:
        conta_memoria()
        return (False, encontrar_ciclo(G, corda_faltando[0],
                                       corda_faltando[1]))

    conta_memoria()
    return (True, OEP[::-1])
Ejemplo n.º 4
0
def tem_corda(G, ciclo):
    tamanho_ciclo = len(ciclo)

    for indice_v, v in enumerate(ciclo):
        for u in G.vizinhos[v]:
            adjacentes_v = [
                ciclo[indice_v - 1], ciclo[(indice_v + 1) % tamanho_ciclo]
            ]
            if u not in adjacentes_v and u in ciclo:
                conta_memoria()
                return True

    conta_memoria()
    return False
Ejemplo n.º 5
0
def eh_cordal_forca_bruta(G):
    ciclos = achar_ciclos4_forca_bruta(G)

    proibidos = []
    qtd_sem_corda = 0
    for ciclo in ciclos:
        if not tem_corda(G, ciclo):
            proibidos.append(ciclo)
            qtd_sem_corda += 1

    conta_memoria()
    if qtd_sem_corda == 0:
        return (True, qtd_sem_corda, [])

    return (False, qtd_sem_corda, proibidos)
Ejemplo n.º 6
0
def testar_ordem_eliminacao_perfeita(G, ordenacao, predecessores):
    test = [
    ]  #conjunto de pares de vértices que devem ser testados para verificar se formam aresta
    for i in range(len(G.vertices) - 1, -1, -1):  #O(n)
        if predecessores[ordenacao[i]] != []:  #O(1)
            u = predecessores[ordenacao[i]][-1]  #O(1)
            for w in predecessores[ordenacao[
                    i]]:  #para cada vértice na ordenação, verificamos os vizinhos, logo passamos por todas as arestas 2x, então é na ordem de O(n + 2m), considerando o loop exterior
                if u != w:  #O(1)
                    test.append((u, w))  #O(1)

    conta_memoria()
    for u, v in test:
        if u in G.vizinhos[v]:
            continue
        else:
            return (False, (u, v))
    return (True, None)
Ejemplo n.º 7
0
def encontrar_ciclo(G, u, v):
    caminhos = []
    while True:
        caminho = caminho_de_u_ate_v(
            G,
            u,
            v,
            caminho_proibido=[v for caminho in caminhos for v in caminho])

        if caminho == []:
            conta_memoria()
            break

        caminhos.append(caminho)

    ciclo = []
    for i in range(0, len(caminhos) - 1):
        for j in range(i + 1, len(caminhos)):
            ciclo = [u] + caminhos[i][::-1] + [v] + caminhos[j]
            if not tem_corda(G, ciclo):
                conta_memoria()
                return ciclo

    conta_memoria()
    return []
Ejemplo n.º 8
0
def achar_ciclos4_forca_bruta(G):
    ciclos = []  #variável que contém todos os ciclos únicos encontrados
    for v in G.vertices:  #percorremos a partir de cada um dos vértices
        vertice_inicial = v
        pilha = deque(
        )  #um conteiner que contém todos os caminhos que iniciam a partir do vértice_inicial (poderia ser qualquer conteiner, na real)
        pilha.append([vertice_inicial
                      ])  #o caminho inicial começa com o vértice_inicial

        while pilha:  #enquanto a pilha não estiver vazia
            caminho_ate_v = pilha.pop()  #removemos algum caminho do conteiner
            v = caminho_ate_v[-1]  #último vértice do caminho até o momento

            for u in G.vizinhos[
                    v]:  #para continuar o caminho, percorremos os vizinhos do último vértice
                if u == vertice_inicial:  #caso um dos vizinhos seja o vertice_inicial, então formamos um ciclo que começa e termina em vertice_inicial
                    if len(
                            caminho_ate_v
                    ) > 3:  #para o problema de grafos cordais (força bruta), queremos apenas os ciclos de tamanho 4 ou maiores
                        novo_ciclo = caminho_ate_v
                        ciclo_duplicado = any(
                            [ciclos_sao_iguais(novo_ciclo, c) for c in ciclos]
                        )  #verificamos se o novo ciclo já foi encontrado anteriormente (pode estar permutado)

                        if not ciclo_duplicado:  #se o ciclo é diferente de todos os outros até agora
                            ciclos.append(novo_ciclo.copy(
                            ))  #novo ciclo é adicionado aos ciclos encontrados

                elif u not in caminho_ate_v:  #caso o vizinho u seja diferente do vértice inicial, precisamos saber se u já não está no caminho (formaria um ciclo com 'folhas')
                    caminho_ate_u = caminho_ate_v[:]  #cópia do caminho
                    caminho_ate_u.append(
                        u)  #vizinho u é adicionado ao novo caminho
                    pilha.append(
                        caminho_ate_u)  #novo caminho é adicionado na pilha
            conta_memoria()
    return ciclos
Ejemplo n.º 9
0
args = parser.parse_args()

if not utils.hp:
	print("Módulo guppy não encontrado. Não será possível contar a memória utilizada pelos algoritmos!\nPara instalar o módulo guppy, use esse comando no cmd/terminal: pip install -U guppy3")
elif args.contar_memoria:
	print("<<CUIDADO: O contador de memória deixa a execução dos algoritmos significantemente mais devagar>>")
else:
	utils.hp = None

arquivo = args.arquivo
g = Grafo(arquivo)
print("Grafo carregado:")
print(g)
if args.metodo in {"fb", "forca_bruta"}:
	print("Executando o algoritmo força bruta")
	mem_antes = utils.conta_memoria()
	saida_fb = forca_bruta.eh_cordal_forca_bruta(g)
	mem_utilizada = utils.conta_memoria() - mem_antes
	if saida_fb[0] == False:
		print("O grafo não é cordal!")
		print(str(saida_fb[1]) + " dos ciclos de tamanho > 3 não contêm cordas")
		print("Subgrafo(s) proibido(s) encontrado(s): ")

		for proibido in saida_fb[2]:
			print(", ".join(proibido))
	else:
		print("O grafo é cordal!")
	
	if args.contar_memoria:
		print("Memória utilizada: " + str(mem_utilizada / 1000.0) + " KB")