코딩테스트/백준
[백준][C++]1707번 이분 그래프
윤깡패
2023. 7. 12. 16:30
문제
https://www.acmicpc.net/problem/1707
1707번: 이분 그래프
입력은 여러 개의 테스트 케이스로 구성되어 있는데, 첫째 줄에 테스트 케이스의 개수 K가 주어진다. 각 테스트 케이스의 첫째 줄에는 그래프의 정점의 개수 V와 간선의 개수 E가 빈 칸을 사이에
www.acmicpc.net
풀이
이분 그래프가 불가능하다 ⇒ 기존의 탐색 메커니즘에서 탐색한 노드에 다시 접근하게 됐을 때 현재 노드의 집합과 같은 경우
- 입력된 그래프 데이터를 인접 리스트로 구현한다.
- 모든 노드로 각각 DFS 탐색 알고리즘을 적용해 탐색을 수행한다.
- DFS를 실행할 때 현재 노드에서 연결된 노드 중 이미 방문한 노드가 나와 같은 집합이면 이분 그래프가 아닌 것으로 판별한다.
- 실행 결과가 이분 그래프가 아니면 이후 노드는 탐색하지 않는다.
- 모든 노드로 DFS를 실행하는 이유 : 그래프의 모든 노드가 이어져 있지 않고, 여러 개의 부분 그래프로 이뤄진 케이스가 존재할 수 있기 때문이다.
그래프(Graph) 자료구조
그래프(Graph) 자료구조 노드와 에지로 구성된 집합 노드(Node) : 데이터를 표현하는 단위 에지(Edge) : 노드를 연결 에지 리스트(Edge List) 노드를 배열에 저장하여 에지 표현 에지를 중심으로 그래프
soobin0821.tistory.com
코드
#include <iostream>
#include <vector>
using namespace std;
void DFS(int node);
static vector<vector<int>> graph;
static vector<bool> visited;
static vector<int> group;
static bool biGraph;
int main()
{
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
int K;
cin >> K;
for(int k = 0; k < K; k++)
{
int V, E;
cin >> V >> E;
graph.resize(V + 1);
visited.resize(V + 1, false);
group.resize(V + 1, 0);
for(int e = 0; e < E; e++)
{
int u, v;
cin >> u >> v;
// graph 인접 리스트에 그래프 데이터 저장
graph[u].push_back(v);
graph[v].push_back(u);
}
biGraph = true;
// 주어진 그래프가 하나로 연결된다는 보장이 없으므로 모든 노드에서 수행
for(int v = 1; v <= V; v++)
{
if(biGraph)
{
DFS(v); // 각 노드에서 DFS 실행
}
else
{
break; // 결과가 이분 그래프가 아니면 반복 종료
}
}
// 이분 그래프 여부를 정답으로 출력
if(biGraph)
{
cout << "YES\n";
}
else
{
cout << "NO\n";
}
// 모든 변수를 다음 테스트 케이스를 위해 초기화
for(int v = 1; v <= V; v++)
{
graph[v].clear();
visited[v] = false;
group[v] = 0;
}
}
return 0;
}
// DFS 구현
void DFS(int node)
{
visited[node] = true; // visited 배열에 현재 노드 방문 기록
for(int next : graph[node])
{
if(visited[next])
{
if(group[next] == group[node])
{
biGraph = false; // 이미 방문한 노드가 현재 노드와 같은 집합이면 이분 그래프가 아님
}
}
else
{
group[next] = (group[node] + 1) % 2; // 인접한 노드는 같은 집합이 아니므로 이전 노드와 다른 집합으로 처리
DFS(next); // DFS 실행(재귀형태)
}
}
}
오답
- 사이클이 발생하여 이분 그래프가 불가능한 경우 판별
⇒ 2개의 집합을 각각 A, B로 표현하여 이분 그래프 집합 배열에 저장한다.
- DFS를 수행하여 이미 방문했던 노드에 도착했을 때, 나와 같은 집합(A or B)이면 이분 그래프 X
- 모든 노드에서 실행 → 실행 결과가 이분 그래프가 아니면 이후 노드는 탐색 X
- 모든 변수를 다음 테스트 케이스를 위해 초기화한다.
더보기
#include <iostream>
#include <vector>
using namespace std;
void DFS(int node);
static vector<vector<int>> A;
static vector<int> check;
static vector<bool> visited;
static bool IsEven;
int main()
{
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
int N;
cin >> N;
for(int t = 0; t < N; t++)
{
int V, E;
cin >> V >> E;
A.resize(V + 1);
visited.resize(V + 1);
check.resize(V + 1);
IsEven = true;
for(int i = 0; i < E; i++)
{
int S, E;
cin >> S >> E;
// A 인접 리스트에 그래프 데이터 저장
A[S].push_back(E);
A[E].push_back(S);
}
// 주어진 그래프가 하나로 연결된다는 보장이 없으므로 모든 노드에서 수행
for(int i = 1; i <= V; i++)
{
if(IsEven)
{
DFS(i);
}
else
{
break; // 결과가 이분 그래프가 아니면 반복 종료
}
}
// 이분 그래프 여부를 정답으로 출력
if(IsEven)
{
cout << "YES" << "\n";
}
else
{
cout << "NO" << "\n";
}
// 모든 변수를 다음 테스트 케이스를 위해 초기화
for(int i = 0; i <= V; i++)
{
A[i].clear();
visited[i] = false;
check[i] = 0;
}
}
}
// DFS 구현
void DFS(int node)
{
visited[node] = true; // visited 배열에 현재 노드 방문 기록
for(int i : A[node])
{
// 인접한 노드는 같은 집합이 아니므로 이전 노드와 다른 집합으로 처리
if(!visited[i])
{
check[i] = (check[node] + 1) % 2;
DFS(i); // DFS 실행(재귀 형태)
}
// 이미 방문한 노드가 현재 노드와 같은 집합이면 이분 그래프가 아님
else if(check[node] == check[i])
{
IsEven = false;
}
}
}
[ 정답코드 예시 ]
• 2개의 집합을 각각 0, 1로 표현
⇒ check[i] = (check[node] + 1) % 2;
• 모든 변수를 다음 테스트 케이스를 위해 초기화
- A[i].clear();
- visited[i] = false;
- check[i] = 0;
728x90