DFS 스패닝 트리를 생성
스패닝 트리를 생성하는 과정에서 방문 순서 기록
문제에서 그래프는 항상 연결되어 있다고 했으니까 DFS 1회 진행하면 답을 찾을 수 있음
#include <iostream>
#include <algorithm>
#include <vector>
#include <unordered_map>
#include <set>
using namespace std;
int V,E;
unordered_map<int ,vector<int>> graph;
vector<int> visited;
set<pair<int, int>> bridges;
int time_count=1;
int dfs(int curent, int parent)
{
// 방문 여부 + 방문 시간 기록
visited[curent] = time_count++;
// 현재 서브트리에서 도달 가능한 가장 낮은 방문 시간
// 모든 노드는 초기에 자기 자신까지만 도달 가능
int low_node_value = visited[curent];
// 이웃 노드를 자식으로 취급
for (auto child : graph[curent])
{
// 바로 되돌아가는 역방향 간선은 차단
if (child == parent) continue;
// 이미 방문한 경우 (사이클이 있는 경우)
if (visited[child] != 0)
{
// 자신의 방문 순서와 도달 가능한 가장 낮은 방문 시간 중 작은 값으로 갱신
low_node_value = min(low_node_value, visited[child]);
continue;
}
// 재귀를 통해서 서브트리를 탐색
// 여기서 서브트리가 도달 가능한 가장 낮은 방문 시간 값 나옴
int subtree = dfs(child, curent);
// 서브트리 값이랑, 내 방문 순서랑 비교해서 작은걸로 갱신
low_node_value = min(low_node_value, subtree);
// 서브 트리의 순번이 부모보다 큰 경우 브릿지임
if (subtree > visited[curent])
{
bridges.insert({min(curent,child), max(curent,child)});
}
}
return low_node_value;
}
int main()
{
ios_base::sync_with_stdio(0);
cin.tie(0);
cin >> V >> E;
for (int i=0; i<E; i++)
{
int u,v;
cin >> u >> v;
graph[u].push_back(v);
graph[v].push_back(u);
}
visited.resize(V+1,0);
dfs(1, 0);
cout << bridges.size() << "\n";
for (auto p : bridges)
cout << p.first << " " << p.second << "\n";
return 0;
}