Problem:
Articulation Points Find articulation points of a given undirected graph G(V, E) . A vertex in an undirected graph is an articulation point (or cut vertex) iff removing it disconnects the graph. Input  |V|  |E|  s 0  t 0  s 1  t 1 : s |E|-1  t |E|-1  , where |V| is the number of vertices and |E| is the number of edges in the graph. The graph vertices are named with the numbers 0, 1,..., |V| -1 respectively.  s i and t i represent source and target verticess of i -th edge (undirected). Output A list of articulation points of the graph G ordered by name. Constraints  1 ≤ |V| ≤ 100,000  0 ≤ |E| ≤ 100,000  The graph is connected  There are no parallel edges  There are no self-loops  Sample Input 1 4 4
0 1
0 2
1 2
2 3 Sample Output 1 2 Sample Input 2 5 4
0 1
1 2
2 3
3 4 Sample Output 2 1
2
3

Solution (Python):


import sys

sys.setrecursionlimit(10 ** 9)
def input(): return sys.stdin.readline().strip()
def INT(): return int(input())
def MAP(): return map(int, input().split())
def LIST(): return list(map(int, input().split()))
INF=float('inf')

N,M=MAP()
nodes=[[] for i in range(N)]
for i in range(M):
    u,v=MAP()
    nodes[u].append(v)
    nodes[v].append(u)

visited=[False]*N
timer=1
prenum=[0]*(N+1)
parent=[0]*(N+1)
lowest=[0]*(N+1)
def rec(cur, prev):
    global timer
    
    prenum[cur]=lowest[cur]=timer
    timer+=1

    visited[cur]=True
    for nxt in nodes[cur]:
        if not visited[nxt]:
            
            parent[nxt]=cur
            rec(nxt, cur)
            
            lowest[cur]=min(lowest[cur], lowest[nxt])
        elif nxt!=prev:
            
            lowest[cur]=min(lowest[cur], prenum[nxt])


rec(0, -1)


ap=set()

np=0
for i in range(1, N):
    p=parent[i]
    if p==0:
        np+=1
    
    elif prenum[p]<=lowest[i]:
        ap.add(p)

if np>1:
    ap.add(0)

ap=sorted(ap)
for a in ap:
    print(a)

Solution (Python):
import sys


from collections import deque
sys.setrecursionlimit(1000000)


def dfs(current, prev):
    global time
    
    ord[current] = time
    low[current] = time
    time += 1
    color[current] = BLACK

    for next in G[current]:
        if color[next] == WHITE:
            
            parent[next] = current
            dfs(next, current)

            
            low[current] = min(low[current], low[next])
        elif next != prev:
            
            low[current] = min(low[current], ord[next])


def art_points():
    global time
    time = 1
    dfs(0, -1)  
    np = 0
    for i in range(1, v):
        p = parent[i]
        if p == 0:
            np += 1
        elif ord[p] <= low[i]:
            ap.add(p)
    if np > 1:
        ap.add(0)


G = {}
v, n = map(int, input().split())
for i in range(0, v):
    G[i] = []
for i in range(n):
    s, t = map(int, input().split())
    G[s].append(t)
    G[t].append(s)
WHITE = 0
BLACK = 2

color = [WHITE] * (v)
parent = [0] * (v)
ord = [0] * (v)
low = [0] * (v)
parent = [0] * (v)
ap = set([])
art_points()
if ap:
    print(*sorted(ap), sep='\n')

Solution (Python):
from sys import stdin
readline = stdin.readline


def main():
    v, e = map(int, readline().split())
    from collections import defaultdict
    g = defaultdict(list)

    for _ in range(e):
        s, t = map(int, readline().split())
        g[s].append(t)
        g[t].append(s)

    visited = set()
    lowest = [None] * v
    parent = [None] * v
    prenum = [None] * v
    child = defaultdict(list)
    root = 0

    
    stack = [(root, None)]
    while stack:
        u, prev = stack.pop()
        if u not in visited:
            parent[u] = prev
            if prev is not None:
                child[prev].append(u)
            visited |= {u}
            prenum[u] = lowest[u] = len(visited)

        stack.extend([(v, u) for v in g[u] if v not in visited])

    
    from collections import Counter
    leaf = [i for i in range(v) if not child[i]]
    unfinished = Counter()
    for li in leaf:
        while li is not None:
            candidate = [prenum[li]] + [prenum[i] for i in g[li] if i != parent[li]] + [lowest[i] for i in child[li]]
            lowest[li] = min(candidate)
            li = parent[li]
            if li is not None and 1 < len(child[li]):
                unfinished[li] += 1
                if unfinished[li] < len(child[li]):
                    break

    
    if 2 <= len(child[root]):
        print(root)
    for i in range(1, v):
        if child[i] and any(prenum[i] <= lowest[j] for j in child[i]):
            print(i)
main()

Solution (Python):
__author__ = 'zhewang711'
import sys
sys.setrecursionlimit(200000)
class Graph:
    def __init__(self):
        self.vertices = 0
        self.outgoing = {}
        self.root_cnt = 0
        
        self.result = set()

    def insert_vertice(self):
        self.vertices += 1
        self.outgoing[self.vertices - 1] = []
        

    def insert_edge(self, s, d):
        if s >= self.vertices or d >= self.vertices:
            raise ValueError('edge cannot be inserted because vertex do not exist')
        else:
            self.outgoing[s].append(d)
            self.outgoing[d].append(s)

    def get_input(self):
        s = input()
        V, E = int(s.split()[0]), int(s.split()[1])
        self.discovery = [None for i in range(V)]
        self.clock = 0
        self.explored = [False for i in range(V)]
        self.father = [None for i in range(V)]
        self.backing = [None for i in range(V)]
        self.sub_have_backing = [None for i in range(V)]
        self.is_leaf = [None for i in range(V)]
        for i in range(V):
            self.insert_vertice()
        for i in range(E):
            s = input()
            self.insert_edge(int(s.split()[0]), int(s.split()[1]))



    def read_input(self, filename):
        f = open(filename, 'r')
        cnt = 0
        for line in f:
            if cnt == 0:
               cnt += 1
               V, E = int(line.split()[0]), int(line.split()[1])

               self.discovery = [None for i in range(V)]
               self.clock = 0
               self.explored = [False for i in range(V)]
               self.father = [None for i in range(V)]
               self.backing = [None for i in range(V)]
               self.sub_have_backing = [False for i in range(V)]
               self.is_leaf = [None for i in range(V)]

               for i in range(V):
                   self.insert_vertice()
            else:
                self.insert_edge(int(line.split()[0]), int(line.split()[1]))

    def DFS(self, root):
        self.explored[root] = True
        self.discovery[root] = self.clock
        self.backing[root] = self.clock
        self.clock += 1
        self.is_leaf[root] = True
        for ver in self.outgoing[root]:
            if not self.explored[ver]:
                self.is_leaf[root] = False
                self.DFS(ver)
                self.backing[root] = min(self.backing[root], self.backing[ver])
            else:
                self.backing[root] = min(self.backing[root], self.discovery[ver])

    def _critical_points(self, root):
        self.explored[root] = True
        self.discovery[root] = self.clock
        self.clock += 1
        for ver in self.outgoing[root]:
            if not self.explored[ver]:
                if root == 0:
                    self.root_cnt += 1
                if self.backing[ver] >= self.discovery[root] and root !=0 and not self.is_leaf[root]:
                    self.result.add(root)
                self._critical_points(ver)

g = Graph()
g.get_input()

g.DFS(0)
g.clock = 0
g.discovery = [None for i in range(g.vertices)]
g.explored = [False for i in range(g.vertices)]
g._critical_points(0)
if g.root_cnt >= 2:
    g.result.add(0)
l = sorted(g.result)
for i in l:
    print(i)

Solution (Python):
import sys

sys.setrecursionlimit(200000)

n, m = map(int, input().split())

edges = [set() for _ in range(n)]

for _ in range(m):
    s, t = map(int, input().split())
    edges[s].add(t)
    edges[t].add(s)

prenum = [None] * n
parent = [None] * n
lowest = [None] * n
counter = 0


def dfs(cur, prev):
    global counter
    prenum[cur] = lowest[cur] = counter
    counter += 1
    for edge in edges[cur]:
        if prenum[edge] is not None:
            if edge != prev:
                lowest[cur] = min(lowest[cur], prenum[edge])
            continue
        parent[edge] = cur
        dfs(edge, cur)
        lowest[cur] = min(lowest[cur], lowest[edge])


dfs(0, 1)
ap = [False] * n
r = 0
for _ in filter(lambda x: x == 0, parent):
    r += 1
    if r > 1:
        ap[0] = True
        break

for i in range(1, n):
    p = parent[i]
    if p and prenum[p] <= lowest[i]:
        ap[p] = True

for i, e in enumerate(ap):
    if e: print(i)

Solution (Python):


import sys

f_i = sys.stdin

V, E = map(int, f_i.readline().split())

adj_sets = [set() for i in range(V)]

for l_i in f_i:
    s, t = map(int, l_i.split())
    adj_sets[s].add(t)
    adj_sets[t].add(s)




prenum = [0] * V
parent = [0] * V
lowest = [V] * V

import collections

path = collections.deque()
path.append(0)

cnt = 0

while path:
    u = path[-1]
    adj_v = adj_sets[u].copy()
    v_candidate = adj_v.difference(path)
    if v_candidate:
        v = v_candidate.pop()
        cnt += 1
        prenum[v] = cnt
        parent[v] = u
        path.append(v)
        adj_sets[u].remove(v)
        adj_sets[v].remove(u)
    else:
        l = min(prenum[u], lowest[u])
        for v in adj_v:
            l = min(l, prenum[v])
            adj_sets[u].remove(v)
            adj_sets[v].remove(u)
        lowest[u] = l
        p = parent[u]
        lowest[p] = min(l, lowest[p])
        path.pop()




ans = set()

for u in range(1, V):
    p = parent[u]
    if prenum[p] <= lowest[u]:
        ans.add(p)

if parent.count(0) >= 3:
    ans.add(0)
else:
    ans.discard(0)

ans = list(ans)
ans.sort()

if ans:
    print(*ans, sep = '\n')

Solution (Python):


import sys

f_i = sys.stdin

V, E = map(int, f_i.readline().split())

adj = [[] for i in range(V)]

for l_i in f_i:
    s, t = map(int, l_i.split())
    adj[s].append(t)
    adj[t].append(s)




prenum = [1] + [None] * (V - 1)
parent = [0] * V
lowest = [V] * V

import collections

path = collections.deque()
path.append(0)

cnt = 1

while path:
    u = path[-1]
    adj_v = adj[u]
    for v in adj_v:
        if not prenum[v]:
            parent[v] = u
            path.append(v)
            cnt += 1
            prenum[v] = cnt
            adj[u].remove(v)
            adj[v].remove(u)
            break
    if u == path[-1]:
        for v in adj_v:
            lowest[u] = min(lowest[u], prenum[v])
            adj[u].remove(v)
            adj[v].remove(u)
        p = parent[u]
        lowest[p] = min(lowest[u], lowest[p])
        path.pop()




ans = set()

for u in range(1, V):
    p = parent[u]
    if prenum[p] <= lowest[u]:
        ans.add(p)

if parent.count(0) >= 3:
    ans.add(0)
else:
    ans.discard(0)

ans = list(ans)
ans.sort()

if ans:
    print(*ans, sep = '\n')

Solution (Python):


import sys

f_i = sys.stdin

V, E = map(int, f_i.readline().split())

adj = [[] for i in range(V)]

for l_i in f_i:
    s, t = map(int, l_i.split())
    adj[s].append(t)
    adj[t].append(s)




prenum = [1] + [None] * (V - 1)
parent = [0] * V
lowest = [V] * V

import collections

path = collections.deque()
path.append(0)

cnt = 1

while path:
    u = path[-1]
    adj_v = adj[u]
    for v in adj_v:
        if not prenum[v]:
            parent[v] = u
            path.append(v)
            cnt += 1
            prenum[v] = cnt
            adj[u].remove(v)
            adj[v].remove(u)
            break
    if u == path[-1]:
        for v in adj_v:
            lowest[u] = min(lowest[u], prenum[v])
        p = parent[u]
        lowest[p] = min(lowest[u], lowest[p])
        path.pop()




ans = set()

for u in range(1, V):
    p = parent[u]
    if prenum[p] <= lowest[u]:
        ans.add(p)

if parent.count(0) >= 3:
    ans.add(0)
else:
    ans.discard(0)

ans = list(ans)
ans.sort()

if ans:
    print(*ans, sep = '\n')

Solution (Python):



"""

input:
5 4
0 1
1 2
2 3
3 4

output:
1
2
3
"""

import sys

sys.setrecursionlimit(int(3e6))
UNVISITED, VISITED_IN_STACK, POPPED_OUT = 0, 1, 2


def generate_adj_table(_v_info):
    for v_detail in _v_info:
        v_from, v_to = map(int, v_detail)
        init_adj_table[v_from].append(v_to)
        
        init_adj_table[v_to].append(v_from)
    return init_adj_table


def graph_dfs(current, prev):
    global timer
    pre_v[current] = lowest_v[current] = timer
    timer += 1

    color[current] = VISITED_IN_STACK

    for adj in adj_table[current]:
        if color[adj] is UNVISITED:
            parent_v[adj] = current

            
            graph_dfs(adj, current)

            lowest_v[current] = min(lowest_v[current], lowest_v[adj])
        elif adj is not prev:
            lowest_v[current] = min(lowest_v[current], pre_v[adj])

    return None


def art_points():
    graph_dfs(dfs_root, -1)

    np = 0
    for v in range(1, vertices):
        parent = parent_v[v]
        if parent is dfs_root:
            np += 1
        elif pre_v[parent] <= lowest_v[v]:
            art_set.add(parent)

    if np > 1:
        art_set.add(dfs_root)

    return art_set


if __name__ == '__main__':
    _input = sys.stdin.readlines()
    vertices, edges = map(int, _input[0].split())
    v_info = map(lambda x: x.split(), _input[1:])
    pre_v, parent_v, lowest_v = ([0] * vertices for _ in range(3))
    init_adj_table = tuple([] for _ in range(vertices))

    timer = 1
    
    dfs_root = 0

    art_set = set()
    color = [UNVISITED] * vertices

    adj_table = generate_adj_table(v_info)

    res = art_points()
    if not res:
        pass
    else:
        
        print(*sorted(res), sep='\n')

Solution (Python):



"""

input:
5 4
0 1
1 2
2 3
3 4

output:
1
2
3
"""

import sys

sys.setrecursionlimit(int(3e6))
UNVISITED, VISITED_IN_STACK, POPPED_OUT = 0, 1, 2


def generate_adj_table(_v_info):
    for v_detail in _v_info:
        v_from, v_to = map(int, v_detail)
        init_adj_table[v_from].append(v_to)
        
        init_adj_table[v_to].append(v_from)
    return init_adj_table


def graph_dfs(current, prev):
    global timer
    pre_v[current] = lowest_v[current] = timer
    timer += 1
    

    color[current] = VISITED_IN_STACK

    for adj in adj_table[current]:
        if color[adj] is UNVISITED:
            parent_v[adj] = current

            
            graph_dfs(adj, current)

            lowest_v[current] = min(lowest_v[current], lowest_v[adj])
        elif adj is not prev:
            lowest_v[current] = min(lowest_v[current], pre_v[adj])

    return None


def art_points():
    graph_dfs(dfs_root, -1)

    np = 0
    for v in range(1, vertices):
        parent = parent_v[v]
        if parent is dfs_root:
            np += 1
        elif pre_v[parent] <= lowest_v[v]:
            art_set.add(parent)

    if np > 1:
        art_set.add(dfs_root)

    return art_set


if __name__ == '__main__':
    _input = sys.stdin.readlines()
    vertices, edges = map(int, _input[0].split())
    v_info = map(lambda x: x.split(), _input[1:])
    pre_v, parent_v, lowest_v = ([-1] * vertices for _ in range(3))
    init_adj_table = tuple([] for _ in range(vertices))

    timer = 1
    
    dfs_root = 0

    art_set = set()
    color = [UNVISITED] * vertices

    adj_table = generate_adj_table(v_info)

    res = art_points()
    
    if not res:
        pass
    else:
        
        print(*sorted(res), sep='\n')

Solution (Python):



"""

input:
5 4
0 1
1 2
2 3
3 4

output:
1
2
3
"""

import sys

sys.setrecursionlimit(int(3e6))
UNVISITED, VISITED_IN_STACK, POPPED_OUT = 0, 1, 2


def generate_adj_table(_v_info):
    for v_detail in _v_info:
        v_from, v_to = map(int, v_detail)
        init_adj_table[v_from].append(v_to)
        
        init_adj_table[v_to].append(v_from)
    return init_adj_table


def graph_dfs(current, prev):
    global timer
    pre_v[current] = lowest_v[current] = timer
    timer += 1

    color[current] = VISITED_IN_STACK
    for adj in adj_table[current]:
        if color[adj] is UNVISITED:
            parent_v[adj] = current
            
            graph_dfs(adj, current)
            lowest_v[current] = min(lowest_v[current], lowest_v[adj])
        elif adj is not prev:
            lowest_v[current] = min(lowest_v[current], pre_v[adj])

    return None


def art_points():
    graph_dfs(dfs_root, -1)

    np = 0
    for v in range(1, vertices):
        parent = parent_v[v]
        if parent is dfs_root:
            np += 1
        elif pre_v[parent] <= lowest_v[v]:
            art_set.add(parent)

    if np > 1:
        art_set.add(dfs_root)

    return art_set


if __name__ == '__main__':
    _input = sys.stdin.readlines()
    vertices, edges = map(int, _input[0].split())
    v_info = map(lambda x: x.split(), _input[1:])
    pre_v, parent_v, lowest_v = ([float('inf')] * vertices for _ in range(3))
    init_adj_table = tuple([] for _ in range(vertices))

    timer = 1
    
    dfs_root = 0

    art_set = set()
    color = [UNVISITED] * vertices

    adj_table = generate_adj_table(v_info)

    res = art_points()
    
    if not res:
        pass
    else:
        print(*sorted(res), sep='\n')

Solution (Python):



"""

input:
5 4
0 1
1 2
2 3
3 4

output:
1
2
3
"""

import sys

sys.setrecursionlimit(int(3e6))
UNVISITED, VISITED_IN_STACK, POPPED_OUT = 0, 1, 2


def generate_adj_table(_v_info):
    for v_detail in _v_info:
        v_from, v_to = map(int, v_detail)
        init_adj_table[v_from].append(v_to)
        
        init_adj_table[v_to].append(v_from)
    return init_adj_table


def graph_dfs(current, prev):
    global timer
    pre_v[current] = lowest_v[current] = timer
    timer += 1

    color[current] = VISITED_IN_STACK
    for adj in adj_table[current]:
        if color[adj] is UNVISITED:
            parent_v[adj] = current
            
            graph_dfs(adj, current)
            lowest_v[current] = min(lowest_v[current], lowest_v[adj])
        elif adj is not prev:
            lowest_v[current] = min(lowest_v[current], pre_v[adj])

    return None


def art_points():
    graph_dfs(dfs_root, -1)

    np = 0
    for v in range(1, vertices):
        parent = parent_v[v]
        if parent is dfs_root:
            np += 1
        elif pre_v[parent] <= lowest_v[v]:
            art_set.add(parent)

    if np > 1:
        art_set.add(dfs_root)

    return art_set


if __name__ == '__main__':
    _input = sys.stdin.readlines()
    vertices, edges = map(int, _input[0].split())
    v_info = map(lambda x: x.split(), _input[1:])
    pre_v, parent_v, lowest_v = ([float('inf')] * vertices for _ in range(3))
    init_adj_table = tuple([] for _ in range(vertices))

    timer = 0
    
    dfs_root = 0

    art_set = set()
    color = [UNVISITED] * vertices

    adj_table = generate_adj_table(v_info)

    res = art_points()
    
    if res:
        print(*sorted(res), sep='\n')

Solution (Python):



"""

input:
5 4
0 1
1 2
2 3
3 4

output:
1
2
3
"""

import sys

sys.setrecursionlimit(int(3e6))
UNVISITED, VISITED_IN_STACK, POPPED_OUT = 0, 1, 2


def generate_adj_table(_v_info):
    for v_detail in _v_info:
        source, target = map(int, v_detail)
        init_adj_table[source].append(target)
        init_adj_table[target].append(source)
    return init_adj_table


def graph_dfs(current, prev):
    global timer
    pre_v[current] = lowest_v[current] = timer
    timer += 1

    color[current] = VISITED_IN_STACK
    for adj in adj_table[current]:
        if color[adj] is UNVISITED:
            parent_v[adj] = current
            
            graph_dfs(adj, current)
            lowest_v[current] = min(lowest_v[current], lowest_v[adj])
        elif adj is not prev:
            lowest_v[current] = min(lowest_v[current], pre_v[adj])

    return None


def art_points():
    graph_dfs(root, -1)

    np = 0
    for v in range(1, vertices):
        parent = parent_v[v]
        if parent is root:
            np += 1
        elif pre_v[parent] <= lowest_v[v]:
            art_set.add(parent)

    if np > 1:
        art_set.add(root)

    return art_set


if __name__ == '__main__':
    _input = sys.stdin.readlines()
    vertices, edges = map(int, _input[0].split())
    v_info = map(lambda x: x.split(), _input[1:])
    pre_v, parent_v, lowest_v = ([float('inf')] * vertices for _ in range(3))
    init_adj_table = tuple([] for _ in range(vertices))
    adj_table = generate_adj_table(v_info)

    timer = 0
    root = 0
    art_set = set()
    color = [UNVISITED] * vertices

    res = art_points()
    if res:
        print(*sorted(res), sep='\n')

Solution (Python):



"""

input:
5 4
0 1
1 2
2 3
3 4

output:
1
2
3
"""

import sys

sys.setrecursionlimit(int(1e6))


def generate_adj_table(_v_info):
    for v_detail in _v_info:
        source, target = map(int, v_detail)
        init_adj_table[source].append(target)
        init_adj_table[target].append(source)
    return init_adj_table


def Tarjan(current, parents, visited, disc, low):
    global timer
    current_children_count = 0
    visited[current] = True
    disc[current] = low[current] = timer
    timer += 1

    for adj in adj_table[current]:
        if not visited[adj]:
            parents[adj] = current
            current_children_count += 1

            Tarjan(adj, parents, visited, disc, low)

            low[current] = min(low[current], low[adj])
            
            if parents[current] == -1 and current_children_count > 1:
                art_set.add(current)

            elif parents[current] != -1 and low[adj] >= disc[current]:
                art_set.add(current)

        elif adj != parents[current]:
            low[current] = min(low[current], disc[adj])

    
    return None


def art_points():
    parents = [-1] * vertices
    visited = [False] * vertices
    disc = [float('inf')] * vertices
    low = [float('inf')] * vertices

    for v in range(vertices):
        Tarjan(v, parents, visited, disc, low)

    return art_set


if __name__ == '__main__':
    _input = sys.stdin.readlines()
    vertices, edges = map(int, _input[0].split())
    v_info = map(lambda x: x.split(), _input[1:])
    init_adj_table = tuple([] for _ in range(vertices))
    adj_table = generate_adj_table(v_info)

    timer = 0
    art_set = set()
    ans = art_points()
    if ans:
        print(*sorted(ans), sep='\n')

Solution (Python):



"""

input:
5 4
0 1
1 2
2 3
3 4

output:
1
2
3
"""

import sys

sys.setrecursionlimit(int(1e6))


def generate_adj_table(_v_info):
    for v_detail in _v_info:
        source, target = map(int, v_detail)
        init_adj_table[source].append(target)
        init_adj_table[target].append(source)
    return init_adj_table


def Tarjan(current, parents, visited, disc, low):
    global timer
    current_children_count = 0
    visited[current] = True
    disc[current] = low[current] = timer
    timer += 1

    for adj in adj_table[current]:
        if not visited[adj]:
            parents[adj] = current
            current_children_count += 1

            Tarjan(adj, parents, visited, disc, low)

            low[current] = min(low[current], low[adj])
            
            if parents[current] == -1 and current_children_count > 1:
                art_set.add(current)

            elif parents[current] != -1 and low[adj] >= disc[current]:
                art_set.add(current)

        elif adj != parents[current]:
            low[current] = min(low[current], disc[adj])

    
    return None


def art_points():
    parents = [-1] * vertices
    visited = [False] * vertices
    disc = [float('inf')] * vertices
    low = [float('inf')] * vertices

    for v in range(vertices):
        if not visited[v]:
            Tarjan(v, parents, visited, disc, low)

    return art_set


if __name__ == '__main__':
    _input = sys.stdin.readlines()
    vertices, edges = map(int, _input[0].split())
    v_info = map(lambda x: x.split(), _input[1:])
    init_adj_table = tuple([] for _ in range(vertices))
    adj_table = generate_adj_table(v_info)

    timer = 0
    art_set = set()
    ans = art_points()
    if ans:
        print(*sorted(ans), sep='\n')

Solution (Python):



"""

input:
5 4
0 1
1 2
2 3
3 4

output:
1
2
3
"""

import sys

sys.setrecursionlimit(int(1e6))


def generate_adj_table(_v_info):
    for v_detail in _v_info:
        source, target = map(int, v_detail)
        init_adj_table[source].append(target)
        init_adj_table[target].append(source)
    return init_adj_table


def Tarjan(current, parents, visited, disc, low):
    global timer
    current_children_count = 0
    visited[current] = True
    disc[current] = low[current] = timer
    timer += 1

    for adj in adj_table[current]:
        if not visited[adj]:
            parents[adj] = current
            current_children_count += 1

            Tarjan(adj, parents, visited, disc, low)

            low[current] = min(low[current], low[adj])
            
            if parents[current] == -1 and current_children_count > 1:
                art_set.add(current)
            elif parents[current] != -1 and low[adj] >= disc[current]:
                art_set.add(current)

        elif adj != parents[current]:
            low[current] = min(low[current], disc[adj])

    return None


def art_points():
    parents = [-1] * vertices
    visited = [False] * vertices
    disc = [float('inf')] * vertices
    low = [float('inf')] * vertices

    for v in range(vertices):
        if not visited[v]:
            Tarjan(v, parents, visited, disc, low)

    return art_set


if __name__ == '__main__':
    _input = sys.stdin.readlines()
    vertices, edges = map(int, _input[0].split())
    v_info = map(lambda x: x.split(), _input[1:])
    init_adj_table = tuple([] for _ in range(vertices))
    adj_table = generate_adj_table(v_info)

    timer = 0
    art_set = set()

    ans = art_points()
    if ans:
        print(*sorted(ans), sep='\n')

Solution (Python):



"""

input:
5 4
0 1
1 2
2 3
3 4

output:
1
2
3
"""

import sys

sys.setrecursionlimit(int(1e5))


def dfs_Tarjan(current):
    global timer
    children = 0
    visited[current] = True
    disc[current] = low[current] = timer
    timer += 1

    for adj in adj_table[current]:
        if not visited[adj]:
            parent[adj] = current
            children += 1
            dfs_Tarjan(adj)
            low[current] = min(low[current], low[adj])
            
            if parent[current] == -1 and children > 1:
                art_set.add(current)
            elif parent[current] != -1 and low[adj] >= disc[current]:
                art_set.add(current)

        elif adj != parent[current]:
            low[current] = min(low[current], disc[adj])

    return None


def dfs_init():
    for v in range(v_num):
        if not visited[v]:
            dfs_Tarjan(v)

    return None


if __name__ == '__main__':
    _input = sys.stdin.readlines()
    v_num, e_num = map(int, _input[0].split())
    edges = map(lambda x: x.split(), _input[1:])

    adj_table = tuple([] for _ in range(v_num))
    for edge in edges:
        source, target = map(int, edge)
        adj_table[source].append(target)
        adj_table[target].append(source)

    timer = 0
    art_set = set()
    parent = [-1] * v_num
    visited = [False] * v_num
    disc, low = ([float('inf')] * v_num for _ in range(2))

    dfs_init()
    if art_set:
        print(*sorted(art_set), sep='\n')

Solution (Python):



"""

input:
5 4
0 1
1 2
2 3
3 4

output:
1
2
3
"""

import sys

sys.setrecursionlimit(int(1e5))


def dfs_Tarjan(current):
    global timer
    children = 0
    visited[current] = True
    disc[current] = low[current] = timer
    timer += 1

    for adj in adj_table[current]:
        if not visited[adj]:
            parent[adj] = current
            children += 1
            dfs_Tarjan(adj)
            low[current] = min(low[current], low[adj])
            if parent[current] == -1 and children > 1:
                art_set.add(current)
            elif parent[current] != -1 and low[adj] >= disc[current]:
                art_set.add(current)

        elif adj != parent[current]:
            low[current] = min(low[current], disc[adj])

    return None


def dfs_init():
    for v in range(v_num):
        if not visited[v]:
            dfs_Tarjan(v)

    return None


if __name__ == '__main__':
    _input = sys.stdin.readlines()
    v_num, e_num = map(int, _input[0].split())
    edges = map(lambda x: x.split(), _input[1:])

    adj_table = tuple([] for _ in range(v_num))
    for edge in edges:
        source, target = map(int, edge)
        adj_table[source].append(target)
        adj_table[target].append(source)

    timer = 0
    art_set = set()
    parent = [-1] * v_num
    visited = [False] * v_num
    disc, low = ([float('inf')] * v_num for _ in range(2))

    dfs_init()
    if art_set:
        print(*sorted(art_set), sep='\n')

Solution (Python):



"""

input:
5 4
0 1
1 2
2 3
3 4

output:
1
2
3
"""

import sys

sys.setrecursionlimit(int(1e5))


def dfs_Tarjan(current, visited, disc, low, parent):
    global timer
    children = 0
    visited[current] = True
    disc[current] = low[current] = timer
    timer += 1

    for adj in adj_table[current]:
        if not visited[adj]:
            parent[adj] = current
            children += 1
            dfs_Tarjan(adj, visited, disc, low, parent)
            low[current] = min(low[current], low[adj])
            if parent[current] == -1 and children > 1:
                art_set.add(current)
            elif parent[current] != -1 and low[adj] >= disc[current]:
                art_set.add(current)

        elif adj != parent[current]:
            low[current] = min(low[current], disc[adj])

    return None


def dfs_init():
    parent = [-1] * v_num
    visited = [False] * v_num
    disc, low = ([float('inf')] * v_num for _ in range(2))

    for v in range(v_num):
        if not visited[v]:
            dfs_Tarjan(v, visited, disc, low, parent)

    return None


if __name__ == '__main__':
    _input = sys.stdin.readlines()
    v_num, e_num = map(int, _input[0].split())
    edges = map(lambda x: x.split(), _input[1:])

    adj_table = tuple([] for _ in range(v_num))
    for edge in edges:
        source, target = map(int, edge)
        adj_table[source].append(target)
        adj_table[target].append(source)

    timer = 0
    art_set = set()
    
    dfs_init()
    if art_set:
        print(*sorted(art_set), sep='\n')

Solution (Python):
import sys
sys.setrecursionlimit(100000)

def dfs(v, tm):
    dts[v] = est[v] = tm + 1
    child = 0

    for i in adj[v]:
        if est[i] == float('inf'):
            child += 1
            parents[i] = v
            dfs(i, tm + 1)
            est[v] = min(est[v], est[i])

            if parents[v] is None and child > 1: aps[v] = True
            if parents[v] is not None and est[i] >= dts[v]: aps[v] = True

        elif parents[v] != i:
            est[v] = min(est[v], dts[i])

nv, ne = map(int, input().split(' '))
adj = [[] for _ in range(nv)]
est = [float('inf')] * nv
parents = [None] * nv
aps = [False] * nv
dts = [0] * nv

for _ in range(ne):
    s, t = map(int, input().split(' '))
    adj[s].append(t)
    adj[t].append(s)

dfs(0, 0)

for i in range(nv):
    if aps[i]:
        print(i)