# minimum labelled node to be removed from undirected graph such that there is no cycle | python3 implementation to find the minimum labelled node to be removed such that there is no cycle in the undirected graph ; variables to store if a node v has at - most one back edge and store the depth of the node for the edge ; function to swap the pairs of the graph ; if the second value is greater than x ; put the pair in the ascending order internally ; function to perform the dfs ; initialise with the large value ; storing the depth of this vertex ; mark the vertex as visited ; iterating through the graph ; if the node is a child node ; if the child node is unvisited ; move to the child and increase the depth ; increase according to algorithm ; if the node is not having exactly k backedges ; if the child is already visited and in current dfs ( because colour is 1 ) then this is a back edge ; increase the countadj values ; colour this vertex 2 as we are exiting out of dfs for this node ; function to find the minimum labelled node to be removed such that there is no cycle in the undirected graph ; construct the graph ; mark visited as false for each node ; apply dfs on all unmarked nodes ; if no backedges in the initial graph this means that there is no cycle so , return - 1 ; iterate through the vertices and return the first node that satisfies the condition ; check whether the count sum of small [ v ] and count is the same as the total back edges and if the vertex v can be removed ; 

MAX = 100005
totBackEdges = 0
countAdj = [0 for i in range(MAX)]
small = [0 for i in range(MAX)]
isPossible = [0 for i in range(MAX)]
depth = [0 for i in range(MAX)]
adj = [[] for i in range(MAX)]
vis = [0 for i in range(MAX)]


def change(p, x):
    if (p[1] > x):
        p[1] = x
    if (p[0] > p[1]):

        tmp = p[0]
        p[0] = p[1]
        p[1] = tmp


def dfs(v, p=-1, de=0):
    global vis, totBackEdges
    answer = [100000000, 100000000]
    depth[v] = de
    vis[v] = 1
    isPossible[v] = 1
    for u in adj[v]:
        if ((u ^ p) != 0):
            if (vis[u] == 0):
                x = dfs(u, v, de + 1)
                small[v] += small[u]

                change(answer, x[1])
                change(answer, x[0])
                if (x[1] < de):
                    isPossible[v] = 0
            elif (vis[u] == 1):
                totBackEdges += 1
                countAdj[v] += 1
                countAdj[u] += 1
                small[p] += 1
                small[u] -= 1
                change(answer, depth[u])
    vis[v] = 2
    return answer


def minNodetoRemove(n, edges):
    for i in range(len(edges)):

        adj[edges[i][0]].append(edges[i][1])
        adj[edges[i][1]].append(edges[i][0])

    global vis, totBackEdges
    vis = [0 for i in range(len(vis))]
    totBackEdges = 0
    for v in range(1, n + 1):
        if (vis[v] == 0):
            dfs(v)
    if (totBackEdges == 0):
        return -1
    node = -1
    for v in range(1, n + 1):
        if ((countAdj[v] + small[v] == totBackEdges) and isPossible[v] != 0):
            node = v
        if (node != -1):
            break
    return node


if __name__ == '__main__':
    N = 5
    edges = []
    edges .append([5, 1])
    edges .append([5, 2])
    edges .append([1, 2])
    edges .append([2, 3])
    edges .append([2, 4])
    print(minNodetoRemove(N, edges))

# Expected output:
1