Home [1707] 이분 그래프
Post
Cancel

[1707] 이분 그래프

문제 링크 : https://www.acmicpc.net/problem/1707

1707 - 이분 그래프

본문

그래프의 정점의 집합을 둘로 분할하여, 각 집합에 속한 정점끼리는 서로 인접하지 않도록 분할할 수 있을 때, 그러한 그래프를 특별히 이분 그래프 (Bipartite Graph) 라 부른다.

그래프가 입력으로 주어졌을 때, 이 그래프가 이분 그래프인지 아닌지 판별하는 프로그램을 작성하시오.

입력

입력은 여러 개의 테스트 케이스로 구성되어 있는데, 첫째 줄에 테스트 케이스의 개수 $K$가 주어진다. 각 테스트 케이스의 첫째 줄에는 그래프의 정점의 개수 $V$와 간선의 개수 $E$가 빈 칸을 사이에 두고 순서대로 주어진다. 각 정점에는 $1$부터 $V$까지 차례로 번호가 붙어 있다. 이어서 둘째 줄부터 $E$개의 줄에 걸쳐 간선에 대한 정보가 주어지는데, 각 줄에 인접한 두 정점의 번호 $u, v$ ($u \neq v$)가 빈 칸을 사이에 두고 주어진다.

출력

$K$개의 줄에 걸쳐 입력으로 주어진 그래프가 이분 그래프이면 YES, 아니면 NO를 순서대로 출력한다.

제한

시간 제한메모리 제한
2sec256MB
  • $2 \leq K \leq 5$
  • $1 \leq V \leq 20\,000$
  • $1 \leq E \leq 200\,000$

풀이

‘이분 그래프’ 라는 개념 자체가 이미 잘 정의되어 있는 개념이었다. 자세한 설명은 하지 않을 예정이니, 궁금하면 직접 찾아보도록 하자.

이분 그래프의 조건을 자세하게 생각해보자. 아무 노드나 하나 선택하면, 그 노드와 직접 연결되어 있는 노드들은 서로 직접 연결되어있으면 안된다. 그러나, 그 노드 사이에 또 다른 노드가 있다면 그 경우는 또 가능한 경우이다. 이렇게 계속 경우를 늘려나가다 보면 얻을 수 있는 정보는 “길이가 1을 제외한 홀수인 사이클은 존재할 수 없다“가 된다. 길이가 짝수인 사이클은 가능.

다만 위 정보는 참고용일 뿐, 이분 그래프의 정의만을 이용해서도 해답을 찾을 수 있다. 아무 노드 $x$를 선택하여 그 노드를 $A$그룹이라고 칭하면, $x$와 직접 연결된 다른 모든 노드를 $B$그룹으로 정하는 것이다. $B$그룹의 노드들과 직접 연결된 모든 노드들은 다시 $A$그룹이라고 칭하고, 이 과정을 반복하는 것이다. 그러다가 같은 그룹의 두 노드가 직접 연결되는 경우가 존재한다면, 그 그래프는 이분 그래프가 될 수 없다는 점을 이용한다.

이것은 bfs를 이용하여 구현할 수 있다. 앞서 얘기했던 방법처럼, 한 노드 $x$를 선택하고 그것을 First 그룹에 넣는다. 이후 bfs를 진행하여 직접 연결된 모든 노드를 Second 그룹에 넣고, 다음 탐색을 진행한다. 어떤 노드 $a$는 이전에 탐색했고 직접 연결된 노드의 그룹에 따라 본인의 그룹이 정해지고, 만약 불가능한 그룹 분배가 나온다면 이분 그래프가 불가능하다고 반환한다.

다만, 문제에서 주어지는 입력들의 경우, 노드들의 그래프가 1개가 아닐 수 있다. 즉 여러 개의 그래프가 존재하므로, 각각의 그래프에 대해서 탐색을 진행하면 된다. bfs 한번에 그래프 1개만을 탐색하므로, 탐색되지 않은 다른 노드에서 추가 탐색을 진행해야한다. 이것은 테스트케이스 안의 visit 배열을 이용하도록 하자.

코드

사용 언어 : C

최종 수정일 : 2023 / 9 / 8

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#include <stdio.h>
#include <stdlib.h>

typedef char bool;
const bool true = 1;
const bool false = 0;

typedef struct Pair {
    int first, second;
} pair;
typedef struct QueueNode {
    int idx, g;
} QN;
typedef struct Node {
    int x;
    struct Node* next;
} ND;

#define MAX_IDX (20000 + 1)
#define MAX_EDGE 200000

const int EMPTY = 0;
const int FIRST = 1;
const int SECOND = 2;

ND* adjacency_list[MAX_IDX + 1];
int v, e;

int group[MAX_IDX + 1];

ND* createNewNode(int x) {
    ND* node = (ND*)malloc(sizeof(ND));
    node->x = x;
    node->next = NULL;
    return node;
}
void free_all() {
    for (int i = 1; i <= v; ++i) {
        ND* cur = adjacency_list[i];

        while (cur != NULL) {
            adjacency_list[i] = cur->next;
            free(cur);
            cur = adjacency_list[i];
        }
    }
    return;
}

void init() {
    for (int i = 1; i <= v; ++i) {
        adjacency_list[i] = NULL;
        group[i] = EMPTY;
    }
    return;
}
void read_input() {
    scanf("%d %d", &v, &e);
    while (e--) {
        int a, b;
        scanf("%d %d", &a, &b);

        ND* newNode = createNewNode(b);
        newNode->next = adjacency_list[a];
        adjacency_list[a] = newNode;

        newNode = createNewNode(a);
        newNode->next = adjacency_list[b];
        adjacency_list[b] = newNode;
    }
    return;
}

bool bfs(int x) {
    QN q[MAX_IDX + 1];
    int front = 0, rear = 0;

    q[rear++] = (QN){x, group[x]};

    while (front < rear) {
        QN cur = q[front++];

        ND* point = adjacency_list[cur.idx];
        while (point != NULL) {
            int target = point->x;

            if (group[target] == group[cur.idx]) {
                return false;
            } else if (group[target] == EMPTY) {
                group[target] = (FIRST + SECOND) - group[cur.idx];
                q[rear++] = (QN){target, group[target]};
            }

            point = point->next;
        }
    }
    return true;
}
bool solve() {
    for (int i = 1; i <= v; ++i) {
        if (group[i] == EMPTY) {
            group[i] = FIRST;

            if (bfs(i) == false) {
                return false;
            }
        }
    }
    return true;
}

int main() {
    int k;
    scanf("%d", &k);

    while (k--) {
        init();
        read_input();
        printf("%s\n", solve() ? "YES" : "NO");
        free_all();
    }

    return 0;
}
This post is licensed under CC BY 4.0 by the author.