coding_test

[99클럽 5기 코테 스터디 TIL 9일차] 이분 그래프(feat. 너비 우선 탐색(BFS))

jeri 2025. 1. 23. 12:23
반응형

1) 문제

https://www.acmicpc.net/problem/1707

 

문제

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

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

입력

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

출력

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

제한

  • 2 ≤ K ≤ 5
  • 1 ≤ V ≤ 20,000
  • 1 ≤ E ≤ 200,000

예제 입력 1 복사

2
3 2
1 3
2 3
4 4
1 2
2 3
3 4
4 2

예제 출력 1 복사

YES
NO

 

2) 학습 풀이

  • 입력 처리:
    • 각 테스트 케이스마다 정점과 간선 정보를 입력받고, 인접 리스트로 그래프를 표현
    • List<Integer>[] graph는 각 정점의 이웃 정점들을 저장
  • 이분 그래프 판별 로직:
    • isBipartite 메서드는 BFS를 사용하여 그래프를 탐색하고 색칠
    • colors 배열은 각 정점의 색을 나타냅니다. 1과 -1로 두 가지 색을 구분
  • 전체 그래프 탐색:
    • 그래프가 연결되어 있지 않을 수 있으므로 모든 정점에서 BFS를 수행
    • 색칠이 충돌하면 즉시 false를 반환하여 이분 그래프가 아님을 판단
  • 출력:
    • 각 테스트 케이스에 대해 "YES" 또는 "NO"를 출력합니다.
import java.io.*;
import java.util.*;

public class Main {
    // BFS로 이분 그래프 판별
    private static boolean isBipartite(List<Integer>[] graph, int[] colors, int start) {
        Queue<Integer> queue = new LinkedList<>();
        queue.add(start);
        colors[start] = 1; // 시작 정점을 1로 색칠

        while (!queue.isEmpty()) {
            int current = queue.poll();

            for (int neighbor : graph[current]) {
                if (colors[neighbor] == 0) { // 이웃 정점이 아직 색칠되지 않았으면
                    colors[neighbor] = -colors[current]; // 다른 색으로 칠함
                    queue.add(neighbor);
                } else if (colors[neighbor] == colors[current]) {
                    // 이웃 정점이 같은 색이면 이분 그래프가 아님
                    return false;
                }
            }
        }
        return true;
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder sb = new StringBuilder();

        int K = Integer.parseInt(br.readLine()); // 테스트 케이스 개수

        for (int t = 0; t < K; t++) {
            StringTokenizer st = new StringTokenizer(br.readLine());
            int V = Integer.parseInt(st.nextToken()); // 정점 개수
            int E = Integer.parseInt(st.nextToken()); // 간선 개수

            // 그래프 초기화
            List<Integer>[] graph = new ArrayList[V + 1];
            for (int i = 1; i <= V; i++) {
                graph[i] = new ArrayList<>();
            }

            // 간선 정보 입력
            for (int i = 0; i < E; i++) {
                st = new StringTokenizer(br.readLine());
                int u = Integer.parseInt(st.nextToken());
                int v = Integer.parseInt(st.nextToken());

                graph[u].add(v);
                graph[v].add(u);
            }

            // 색상 배열 초기화 (0: 미방문, 1: 색1, -1: 색2)
            int[] colors = new int[V + 1];
            boolean isBipartite = true;

            // 모든 정점에 대해 BFS 실행 (연결 그래프가 아닐 수 있으므로)
            for (int i = 1; i <= V; i++) {
                if (colors[i] == 0) { // 아직 방문하지 않은 정점만 탐색
                    if (!isBipartite(graph, colors, i)) {
                        isBipartite = false;
                        break;
                    }
                }
            }

            // 결과 저장
            sb.append(isBipartite ? "YES" : "NO").append("\n");
        }

        // 결과 출력
        System.out.println(sb);
    }
}
반응형