#include <bits/stdc++.h>
using namespace std;
class Graph {
public:
int n, m;
bool isDirected;
vector<vector<int>> adj;
Graph(int nodes, bool isDigraph): adj(nodes){
n = nodes;
m = 0;
isDirected = isDigraph;
}
void insertEdge(int u, int v){
if(u >=n || v >=n || u < 0 || v < 0){
cout<<"Either of the vertices doesn't exists!!\n"
"please enter vertices within range of [0,"<<n<<").\n";
return;
}
if(isDirected || u != v)
adj[u].push_back(v);
if(!isDirected && u != v)
adj[v].push_back(u);
}
void findCutEdgesAndVertices() {
vector<bool> visited(n);
vector<bool> cutVertices(n);
vector<vector<int>> cutEdges;
vector<int> discovery(n), low(n);
int timer = 0;
// Calling with root node of DFS with 0, parent -1 since it has no parent.
// You can call with any node in the graph as root.
dfsTraversal(0, -1, timer, visited, cutVertices, cutEdges, discovery, low);
cout<<"The cut vertices(Articulation Points) in the graph are:,\n";
for(int i=0; i<n; ++i){
if(cutVertices[i])
cout<<i<<" ";
}
cout<<"\n";
cout<<"The cut edges(Bridges) in the graph are:,\n";
for(auto edge: cutEdges){
cout<<edge[0]<<" -> "<<edge[1]<<"\n";
}
cout<<"\n";
}
void dfsTraversal(int u, int parent, int &timer, vector<bool> &visited,
vector<bool> &cutVertices, vector<vector<int>> &cutEdges,
vector<int> &discovery, vector<int> &low){
visited[u] = true;
low[u] = discovery[u] = ++timer;
int children = 0; //Useful for root node in DFS tree.
for(auto v: adj[u]){
if(!visited[v]){
++children;
dfsTraversal(v, u, timer, visited, cutVertices, cutEdges, discovery, low);
low[u] = min(low[u], low[v]);
// If discovery of current node(u) is less than finish of any of its neighbour nodes,
// then it means neighbour(v) has not found any route to another node which is discovered
// before current node(u). Hence, a cut edge.
if(discovery[u] < low[v])
cutEdges.push_back({u, v});
// This is root node of dfs tree with more than 1 child, i.e cutVertex
if(parent == -1 && children > 1)
cutVertices[u] = true;
// This is starting point of cycle if found, i.e cutVertex
else if(parent != -1 && discovery[u] <= low[v])
cutVertices[u] = true;
}
else if(v != parent){
low[u] = min(low[u], low[v]);
}
}
}
};
int main(){
int n, di, m;
cin>>n>>di>>m;
Graph g(n, di);
int u, v;
for(int i = 0; i < m; ++i){
cin>>u>>v;
g.insertEdge(u, v);
}
g.findCutEdgesAndVertices();
return 0;
}
I2luY2x1ZGUgPGJpdHMvc3RkYysrLmg+CnVzaW5nIG5hbWVzcGFjZSBzdGQ7CgpjbGFzcyBHcmFwaCB7CnB1YmxpYzoKCWludCBuLCBtOwoJYm9vbCBpc0RpcmVjdGVkOwoJCiAgICB2ZWN0b3I8dmVjdG9yPGludD4+IGFkajsKICAgIAogICAgR3JhcGgoaW50IG5vZGVzLCBib29sIGlzRGlncmFwaCk6IGFkaihub2Rlcyl7CiAgICAgICAgbiA9IG5vZGVzOwogICAgICAgIG0gPSAwOwogICAgICAgIGlzRGlyZWN0ZWQgPSBpc0RpZ3JhcGg7CiAgICB9CiAgICAKICAgIHZvaWQgaW5zZXJ0RWRnZShpbnQgdSwgaW50IHYpewogICAgCWlmKHUgPj1uIHx8IHYgPj1uIHx8IHUgPCAwIHx8IHYgPCAwKXsKICAgIAkJY291dDw8IkVpdGhlciBvZiB0aGUgdmVydGljZXMgZG9lc24ndCBleGlzdHMhIVxuIgogICAgCQkicGxlYXNlIGVudGVyIHZlcnRpY2VzIHdpdGhpbiByYW5nZSBvZiBbMCwiPDxuPDwiKS5cbiI7CiAgICAJCXJldHVybjsKICAgIAl9CiAgICAJCiAgICAJaWYoaXNEaXJlY3RlZCB8fCB1ICE9IHYpCiAgICAJCWFkalt1XS5wdXNoX2JhY2sodik7CiAgICAgICAgCiAgICAgICAgaWYoIWlzRGlyZWN0ZWQgJiYgdSAhPSB2KQogICAgICAgIAlhZGpbdl0ucHVzaF9iYWNrKHUpOwogICAgfQogICAgCiAgICB2b2lkIGZpbmRDdXRFZGdlc0FuZFZlcnRpY2VzKCkgewogICAgCQogICAgCXZlY3Rvcjxib29sPiB2aXNpdGVkKG4pOwogICAgCgkgICAgdmVjdG9yPGJvb2w+IGN1dFZlcnRpY2VzKG4pOwoJICAgIHZlY3Rvcjx2ZWN0b3I8aW50Pj4gY3V0RWRnZXM7CgkgICAgCgkgICAgdmVjdG9yPGludD4gZGlzY292ZXJ5KG4pLCBsb3cobik7CgkgICAgCgkgICAgaW50IHRpbWVyID0gMDsKICAgICAgICAKICAgICAgICAvLyBDYWxsaW5nIHdpdGggcm9vdCBub2RlIG9mIERGUyB3aXRoIDAsIHBhcmVudCAtMSBzaW5jZSBpdCBoYXMgbm8gcGFyZW50LgogICAgICAgIC8vIFlvdSBjYW4gY2FsbCB3aXRoIGFueSBub2RlIGluIHRoZSBncmFwaCBhcyByb290LgogICAgICAgIGRmc1RyYXZlcnNhbCgwLCAtMSwgdGltZXIsIHZpc2l0ZWQsIGN1dFZlcnRpY2VzLCBjdXRFZGdlcywgZGlzY292ZXJ5LCBsb3cpOwogICAgICAgIAogICAgICAgIGNvdXQ8PCJUaGUgY3V0IHZlcnRpY2VzKEFydGljdWxhdGlvbiBQb2ludHMpIGluIHRoZSBncmFwaCBhcmU6LFxuIjsKICAgICAgICBmb3IoaW50IGk9MDsgaTxuOyArK2kpewogICAgICAgICAgICBpZihjdXRWZXJ0aWNlc1tpXSkKICAgICAgICAgICAgICAgIGNvdXQ8PGk8PCIgIjsKICAgICAgICB9CiAgICAgICAgY291dDw8IlxuIjsKICAgICAgICAKICAgICAgICBjb3V0PDwiVGhlIGN1dCBlZGdlcyhCcmlkZ2VzKSBpbiB0aGUgZ3JhcGggYXJlOixcbiI7CiAgICAgICAgZm9yKGF1dG8gZWRnZTogY3V0RWRnZXMpewogICAgICAgICAgICAgICAgY291dDw8ZWRnZVswXTw8IiAtPiAiPDxlZGdlWzFdPDwiXG4iOwogICAgICAgIH0KICAgICAgICBjb3V0PDwiXG4iOwogICAgfQogICAgCiAgICB2b2lkIGRmc1RyYXZlcnNhbChpbnQgdSwgaW50IHBhcmVudCwgaW50ICZ0aW1lciwgdmVjdG9yPGJvb2w+ICZ2aXNpdGVkLCAKICAgIAkJdmVjdG9yPGJvb2w+ICZjdXRWZXJ0aWNlcywgdmVjdG9yPHZlY3RvcjxpbnQ+PiAmY3V0RWRnZXMsIAogICAgCQl2ZWN0b3I8aW50PiAmZGlzY292ZXJ5LCB2ZWN0b3I8aW50PiAmbG93KXsKICAgIAogICAgICAgIHZpc2l0ZWRbdV0gPSB0cnVlOwogICAgICAgIGxvd1t1XSA9IGRpc2NvdmVyeVt1XSA9ICsrdGltZXI7CiAgICAgICAgCiAgICAgICAgaW50IGNoaWxkcmVuID0gMDsgLy9Vc2VmdWwgZm9yIHJvb3Qgbm9kZSBpbiBERlMgdHJlZS4KICAgICAgICAKICAgICAgICBmb3IoYXV0byB2OiBhZGpbdV0pewogICAgICAgICAgICBpZighdmlzaXRlZFt2XSl7CiAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICsrY2hpbGRyZW47CiAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgIGRmc1RyYXZlcnNhbCh2LCB1LCB0aW1lciwgdmlzaXRlZCwgY3V0VmVydGljZXMsIGN1dEVkZ2VzLCBkaXNjb3ZlcnksIGxvdyk7CiAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgIGxvd1t1XSA9IG1pbihsb3dbdV0sIGxvd1t2XSk7CiAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgIC8vIElmIGRpc2NvdmVyeSBvZiBjdXJyZW50IG5vZGUodSkgaXMgbGVzcyB0aGFuIGZpbmlzaCBvZiBhbnkgb2YgaXRzIG5laWdoYm91ciBub2RlcywKICAgICAgICAgICAgICAgIC8vIHRoZW4gaXQgbWVhbnMgbmVpZ2hib3VyKHYpIGhhcyBub3QgZm91bmQgYW55IHJvdXRlIHRvIGFub3RoZXIgbm9kZSB3aGljaCBpcyBkaXNjb3ZlcmVkCiAgICAgICAgICAgICAgICAvLyBiZWZvcmUgY3VycmVudCBub2RlKHUpLiBIZW5jZSwgYSBjdXQgZWRnZS4KICAgICAgICAgICAgICAgIGlmKGRpc2NvdmVyeVt1XSA8IGxvd1t2XSkKICAgICAgICAgICAgICAgICAgICBjdXRFZGdlcy5wdXNoX2JhY2soe3UsIHZ9KTsKICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgLy8gVGhpcyBpcyByb290IG5vZGUgb2YgZGZzIHRyZWUgd2l0aCBtb3JlIHRoYW4gMSBjaGlsZCwgaS5lIGN1dFZlcnRleAogICAgICAgICAgICAgICAgaWYocGFyZW50ID09IC0xICYmIGNoaWxkcmVuID4gMSkKICAgICAgICAgICAgICAgICAgICBjdXRWZXJ0aWNlc1t1XSA9IHRydWU7CiAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgIC8vIFRoaXMgaXMgc3RhcnRpbmcgcG9pbnQgb2YgY3ljbGUgaWYgZm91bmQsIGkuZSBjdXRWZXJ0ZXgKICAgICAgICAgICAgICAgIGVsc2UgaWYocGFyZW50ICE9IC0xICYmIGRpc2NvdmVyeVt1XSA8PSBsb3dbdl0pCiAgICAgICAgICAgICAgICAgICAgY3V0VmVydGljZXNbdV0gPSB0cnVlOwogICAgICAgICAgICAgICAgCiAgICAgICAgICAgIH0KICAgICAgICAgICAgZWxzZSBpZih2ICE9IHBhcmVudCl7CiAgICAgICAgICAgICAgICBsb3dbdV0gPSBtaW4obG93W3VdLCBsb3dbdl0pOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQp9OwoKCmludCBtYWluKCl7CgkKCWludCBuLCBkaSwgbTsKCWNpbj4+bj4+ZGk+Pm07CgkKCUdyYXBoIGcobiwgZGkpOwoJCglpbnQgdSwgdjsKCQoJZm9yKGludCBpID0gMDsgaSA8IG07ICsraSl7CgkJY2luPj51Pj52OwoJCWcuaW5zZXJ0RWRnZSh1LCB2KTsKCX0KCQoJZy5maW5kQ3V0RWRnZXNBbmRWZXJ0aWNlcygpOwoJCglyZXR1cm4gMDsKfQoK