이분 그래프 (Bipartite Graph)
- 정점의 집합을 둘로 분할하여, 각 집합에 속한 정점끼리는 서로
인접하지 않도록 분할할 수 있는 그래프 - 인접한 정점끼리 서로 다른 색으로 칠해서 모든 정점을 두 가지 색으로만 칠할 수 있는 그래프

이분 그래프 판별하기
DFS를 이용해서 두 가지 색으로 정점 채색을 한다. 이후 모든 정점들을 순회하면서 인접한 정점과의 색이 같은지 확인한다. 만약 색이 같은 경우가 나오면 이분그래프가 아니다.
정점 채색
// DFS for Coloring
int visited[MAX_VERTICES];
void DFS(GraphType* g, int v) {
if (!visited[v])
visited[v] = RED;
if(visited[v] == RED)
printf("정점%d(RED) -> ", v+1);
else
printf("정점%d(BLUE) -> ", v + 1);
for (GraphNode* w = g->adj_list[v]; w; w = w->link) {
if (!visited[w->vertex]) {
if (visited[v] == RED)
visited[w->vertex] = BLUE;
else if (visited[v] == BLUE)
visited[w->vertex] = RED;
DFS(g, w->vertex);
}
}
}
DFS (깊이 우선 탐색): 먼저 정점 v를 방문한 다음, v에 인접한 정점 중에 아직 방문하지 않은 정점 w를 찾아서 w에 대한 DFS를 재귀적으로 수행한다. [ 시간복잡도: O(n+m), n은 정점의 개수, m은 에지의 개수 ]
DFS를 이용해서 정점의 색을 칠해준다. (RED or BLUE)
정점을 방문하지 않았으면 RED로 색칠한다.
현재 방문하고 있는 정점과 인접해있는 정점의 색을 현재 색과 다른 색으로 칠해준다.
(인접해있는 정점 중 아직 방문하지 않은 정점의 색을 다른 색으로 칠해줌)
이분 그래프 체크
bool Bipartite(GraphType* g) {
for (int i = 0; i < g->n; i++) {
GraphNode* p = g->adj_list[i];
int curr = i;
while (p != NULL) {
int next = p->vertex;
// check bipartite
if (visited[curr] == visited[next]) {
printf("[ERROR] %d %d\n", curr + 1, next + 1);
return false;
}
else
printf("[SUCCESS] %d %d\n", curr + 1, next + 1);
// update p
p = p->link;
}
}
return true;
}
연결되어 있는 모든 정점들을 검사한다.
만일 색이 같다면 그 즉시 false를 반환하고 (이분 그래프가 아님)
모든 정점을 검사해도 색이 같은 경우가 없으면 true를 반환한다. (이분그래프)
전체 코드 (C)
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#pragma warning(disable:4996)
#define MAX_VERTICES 100000
#define RED 1
#define BLUE 2
typedef struct GraphNode {
int vertex;
struct GraphNode* link;
}GraphNode;
typedef struct GraphType {
int n; // 정점의 개수
GraphNode* adj_list[MAX_VERTICES];
}GraphType;
// 그래프 초기화
void init(GraphType* g) {
int v;
g->n = 0;
for (v = 0; v < MAX_VERTICES; v++)
g->adj_list[v] = NULL;
}
// 정점 삽입 연산
void insert_vertex(GraphType* g, int v) {
if ((g->n) + 1 > MAX_VERTICES) {
fprintf(stderr, "그래프: 정점의 개수 초과");
return;
}
g->n++;
}
// 간선 삽입 연산, v를 u의 인접 리스트에 삽입한다.
void insert_edge(GraphType* g, int u, int v) {
GraphNode* node;
if (u >= g->n || v >= g->n) {
fprintf(stderr, "그래프: 정점 번호 오류");
return;
}
if (g->adj_list[u] == NULL) { // insert_first
node = (GraphNode*)malloc(sizeof(GraphNode));
node->vertex = v;
node->link = g->adj_list[u];
g->adj_list[u] = node;
}
else { //insert_last
node = g->adj_list[u];
while (node->link != NULL)
node = node->link;
node->link = (GraphNode*)malloc(sizeof(GraphNode));
node->link->vertex = v;
node->link->link = NULL;
}
}
// DFS for Coloring
int visited[MAX_VERTICES];
void DFS(GraphType* g, int v) {
if (!visited[v])
visited[v] = RED;
if(visited[v] == RED)
printf("정점%d(RED) -> ", v+1);
else
printf("정점%d(BLUE) -> ", v + 1);
for (GraphNode* w = g->adj_list[v]; w; w = w->link) {
if (!visited[w->vertex]) {
if (visited[v] == RED)
visited[w->vertex] = BLUE;
else if (visited[v] == BLUE)
visited[w->vertex] = RED;
DFS(g, w->vertex);
}
}
}
// 이분 그래프 체크
bool Bipartite(GraphType* g) {
for (int i = 0; i < g->n; i++) {
GraphNode* p = g->adj_list[i];
int curr = i;
while (p != NULL) {
int next = p->vertex;
// check bipartite
if (visited[curr] == visited[next]) {
printf("[ERROR] %d %d\n", curr + 1, next + 1);
return false;
}
else
printf("[SUCCESS] %d %d\n", curr + 1, next + 1);
// update p
p = p->link;
}
}
return true;
}
// 그래프 출력
void print_adj_list(GraphType* g) {
for (int i = 0; i < g->n; i++) {
GraphNode* p = g->adj_list[i];
printf("정정 %d의 인접 리스트", i+1);
while (p != NULL) {
printf("-> %d", p->vertex+1);
p = p->link;
}
printf("\n");
}
}
int main() {
GraphType* g;
g = (GraphType*)malloc(sizeof(GraphType));
init(g);
// 정점, 에지 개수 입력
int n, m;
scanf("%d %d", &n, &m);
// 정점 삽입
for (int i = 0; i < n; i++)
insert_vertex(g, i);
// 에지 삽입
for (int i = 0; i < m; i++) {
int u, v;
scanf("%d %d", &u, &v);
// 정점이 0부터 시작하므로 1씩 제거
u = u - 1;
v = v - 1;
insert_edge(g, u, v); // vertex(u) -> vertex(v)
insert_edge(g, v, u); // vertex(v) -> vertex(u)
}
print_adj_list(g);
printf("\n");
// DFS로 색칠
DFS(g, 0);
printf("\n");
// 이분그래프 판별
bool output = Bipartite(g);
if (output)
printf("%d", 1);
else
printf("%d", -1);
free(g);
return 0;
}
인접 리스트를 이용한 DFS 구현 + 이분 그래프 판별
[ 시간복잡도: O(n+m), n은 정점의 개수, m은 에지의 개수 ]
테스트 결과 예시


입력: 3 3 (정점 개수, 에지 개수) 2 1 1 3 3 2 (에지)
출력: -1 (이분 그래프가 아님)


입력: 4 4 (정점 개수, 에지 개수) 1 2 2 3 3 4 4 1 (에지)
출력: 1 (이분 그래프)