using System;
using System.Collections.Generic;
class Graph {
private int V;
private List<int>[] adj;
public Graph(int v) {
V = v;
adj = new List<int>[v];
for (int i = 0; i < v; i++) {
adj[i] = new List<int>();
}
}
public void AddEdge(int u, int v) {
adj[u].Add(v);
adj[v].Add(u);
}
private void APUtil(int u, bool[] visited, int[] disc, int[] low, int[] parent, bool[] ap, ref int time) {
visited[u] = true;
disc[u] = low[u] = ++time;
int children = 0;
foreach (int v in adj[u]) {
if (!visited[v]) {
children++;
parent[v] = u;
APUtil(v, visited, disc, low, parent, ap, ref time);
low[u] = Math.Min(low[u], low[v]);
if (parent[u] == -1 && children > 1) {
ap[u] = true;
}
if (parent[u] != -1 && low[v] >= disc[u]) {
ap[u] = true;
}
} else if (v != parent[u]) {
low[u] = Math.Min(low[u], disc[v]);
}
}
}
public void FindArticulationPoints() {
bool[] visited = new bool[V];
int[] disc = new int[V];
int[] low = new int[V];
int[] parent = new int[V];
bool[] ap = new bool[V];
for (int i = 0; i < V; i++) {
parent[i] = -1;
}
int time = 0;
for (int i = 0; i < V; i++) {
if (!visited[i]) {
APUtil(i, visited, disc, low, parent, ap, ref time);
}
}
Console.Write("Articulation points: ");
bool first = true;
for (int i = 0; i < V; i++) {
if (ap[i]) {
if (!first) Console.Write(", ");
Console.Write(i + 1);
first = false;
}
}
Console.WriteLine();
}
}
class Program {
static void Main() {
Graph g = new Graph(5);
g.AddEdge(0, 1);
g.AddEdge(0, 2);
g.AddEdge(1, 2);
g.AddEdge(2, 3);
g.AddEdge(2, 4);
g.FindArticulationPoints();
}
}disc[u] = low[u] = ++time;
Assign discovery time and low value when visiting node u
parent[v] = u;
APUtil(v, visited, disc, low, parent, ap, ref time);
Explore child v of u recursively
low[u] = Math.Min(low[u], low[v]);
Update low[u] based on child's low value
if (parent[u] == -1 && children > 1) {
ap[u] = true;
Root node with multiple children is articulation point
if (parent[u] != -1 && low[v] >= disc[u]) {
ap[u] = true;
Non-root node u is articulation point if child's low >= u's discovery
} else if (v != parent[u]) {
low[u] = Math.Min(low[u], disc[v]);
Update low[u] for back edges to ancestors