Source code for tryalgo.shortest_cycle
#!/usr/bin/env python3
"""\
Find shortest simple cycle
christoph durr, finn voelkel and louis abraham - 2016-2019
O(V*E)
footnote (1) here you can add parity check of cycle_len
if only even cycles are requested
"""
# pylint: disable=bad-whitespace, missing-docstring, multiple-statements
from collections import deque
from sys import stdin
from tryalgo.floyd_warshall import floyd_warshall
def readstr(): return stdin.readline().strip()
def readints(): return map(int, stdin.readline().split())
def readint(): return int(stdin.readline())
__all__ = ["shortest_cycle", "powergraph"]
def bfs(graph, root, prune_level):
    """make a pruned BFS search of the graph starting at root.
    returns the BFS tree, and possibly a traversal edge (u,v)
    that with the tree forms a cycle of some length.
    :param graph: undirected graph in listlist or listdict format
    :param root:  vertex where BFS exploration starts
    :param prune_level: exploration is done only up to
    the prune_level (included)
    :complexity: O(V + E)
    """
    n = len(graph)
    level = [-1] * n                      # -1 == not seen
    tree = [None] * n                     # pointers to predecessors
    to_visit = deque([root])              # queue for BFS
    level[root] = 0
    tree[root] = root
    best_cycle = float('inf')             # start with infinity
    best_u = None
    best_v = None
    while to_visit:
        u = to_visit.popleft()
        if level[u] > prune_level:
            break
        for v in graph[u]:
            if tree[u] == v:              # ignore the tree edge
                continue
            if level[v] == -1:            # new vertex - tree edge
                level[v] = level[u] + 1
                to_visit.append(v)
                tree[v] = u
            else:                        # vertex already seen - traversal edge
                prune_level = level[v] - 1
                cycle_len = level[u] + 1 + level[v]
                if cycle_len < best_cycle:  # footnote (1)
                    best_cycle = cycle_len
                    best_u = u
                    best_v = v
    return tree, best_cycle, best_u, best_v
def path(tree, v):
    """returns the path in the tree from v to the root
    Complexity: O(V)
    """
    P = []
    while not P or P[-1] != v:
        P.append(v)
        v = tree[v]
    return P
[docs]
def shortest_cycle(graph):
    """ Finding a shortest cycle in an undirected unweighted graph
    :param graph: undirected graph in listlist or listdict format
    :returns: None or a list C describing a shortest cycle
    :complexity: `O(|V|*|E|)`
    """
    best_cycle = float('inf')
    best_u = None
    best_v = None
    best_tree = None
    V = list(range(len(graph)))
    for root in V:
        tree, cycle_len, u, v = bfs(graph, root, best_cycle // 2)
        if cycle_len < best_cycle:
            best_cycle = cycle_len
            best_u = u
            best_v = v
            best_tree = tree
    if best_cycle == float('inf'):
        return None                   # no cycle found
    Pu = path(best_tree, best_u)      # combine path to make a cycle
    Pv = path(best_tree, best_v)
    cycle = Pu[::-1] + Pv   # last vertex equals first vertex
    return cycle[1:]        # remove duplicate vertex 
[docs]
def powergraph(graph, k):
    """Compute the k-th
       `powergraph <https://en.wikipedia.org/wiki/Graph_power>`_
       which has an edge u,v for every vertex pair
       of distance at most k in the given graph.
    :param graph: undirected graph in listlist or listdict format
    :param k: non-negative integer.
    :complexity: O(V^3)
    """
    V = range(len(graph))
    # create weight matrix for paths of length 1
    M = [[float('inf') for v in V] for u in V]
    for u in V:
        for v in graph[u]:
            M[u][v] = M[v][u] = 1
        M[u][u] = 0
    floyd_warshall(M)
    return [[v for v in V if M[u][v] <= k] for u in V]