[JAVA] 백준 (골드4) 1707번 이분 그래프

AIR·2024년 5월 10일
0

링크

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


문제 설명

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

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


입력 예제

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

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


출력 예제

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

YES
NO


풀이

우선 이분 그래프에 대해서 개념적으로 알아보면 인접한 정점끼리 서로 다른 색을 칠했을 때 모든 정점을 두 가지 색으로 칠할 수 있는 그래프이다. 다음 그림에서 왼쪽이 이분 그래프에 해당한다.

그래프의 모든 정점이 이어져 있지 않은 경우도 있기 때문에 BFS나 DFS를 이용해서 모든 정점을 탐색하며 인접 노드들 색칠해간다.

isBipartite = true;
color = new Integer[V + 1];
//모든 정점에 대해 탐색
for (int i = 1; i <= V; i++) {
    //이분 그래프가 아닐 시 탐색 중지
    if (isBipartite) {
        bfs(i);
    } else {
        break;
    }
}

인접 노드를 탐색여부를 Integer 배열으로 구분한다. null일 경우 색칠되지 않은 (방문하지 않은) 상태이고 0과 1로 구분하여 노드를 색칠한다.

//인접 노드가 색칠되지 않았을 경우
if (color[adjNode] == null) {
    //현재 노드와 다른 색으로 색칠
    color[adjNode] = 1 - color[curNode];
    queue.add(adjNode);
}
//인접 노드와 현재 노드가 같은 색일 경우 이분 그래프가 아님
else if (color[adjNode].equals(color[curNode])) {
    isBipartite = false;
}

정점이 인접 노드가 존재하지 않을 수도 있으므로 탐색을 수행하기 전 시작 노드에 색칠을 해준다.

//색칠되지 않은 정점일 경우 색칠
if (color[start] == null) {
    color[start] = 1;
}

코드

//백준
public class Main {

    static List<List<Integer>> adjList = new ArrayList<>();
    static Integer[] color;  //각 노드의 색칠 정보
    static boolean isBipartite;  //이분 그래프 여부

    public static void main(String[] args) throws IOException {

        System.setIn(new FileInputStream("src/input.txt"));
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;

        int K = Integer.parseInt(br.readLine());  //테스트 케이스
        for (int testCase = 0; testCase < K; testCase++) {
            st = new StringTokenizer(br.readLine());
            int V = Integer.parseInt(st.nextToken());  //정점의 개수
            int E = Integer.parseInt(st.nextToken());  //간선의 개수

            adjList = new ArrayList<>();
            for (int i = 0; i <= V; i++) {
                adjList.add(new ArrayList<>());
            }
            //인접 리스트 생성
            for (int i = 0; i < E; i++) {
                st = new StringTokenizer(br.readLine());
                int a = Integer.parseInt(st.nextToken());
                int b = Integer.parseInt(st.nextToken());

                adjList.get(a).add(b);
                adjList.get(b).add(a);
            }

            isBipartite = true;
            color = new Integer[V + 1];
            //모든 정점에 대해 탐색
            for (int i = 1; i <= V; i++) {
                //이분 그래프가 아닐 시 탐색 중지
                if (isBipartite) {
					bfs(i);
                    //dfs(i);
                } else {
                    break;
                }
            }

            System.out.println(isBipartite ? "YES" : "NO");
        }

    }
	//너비 우선 탐색
    static void bfs(int start) {
        Queue<Integer> queue = new LinkedList<>();
        queue.add(start);
        //색칠되지 않은 정점일 경우 색칠
        if (color[start] == null) {
            color[start] = 1;
        }

        while (!queue.isEmpty()) {
            int curNode = queue.poll();
            //인접 노드 탐색
            for (Integer adjNode : adjList.get(curNode)) {
                //인접 노드가 색칠되지 않았을 경우
                if (color[adjNode] == null) {
                    //현재 노드와 다른 색으로 색칠
                    color[adjNode] = 1 - color[curNode];
                    queue.add(adjNode);
                }
                //인접 노드와 현재 노드가 같은 색일 경우 이분 그래프가 아님
                else if (color[adjNode].equals(color[curNode])) {
                    isBipartite = false;
                }
            }
        }
    }
	//깊이 우선 탐색
    static void dfs(int curNode) {
        if (color[curNode] == null) {
            color[curNode] = 1;
        }

        for (Integer adjNode : adjList.get(curNode)) {
            if (color[adjNode] == null) {
                color[adjNode] = 1 - color[curNode];
                dfs(adjNode);
            } else if (color[adjNode].equals(color[curNode])) {
                isBipartite = false;
            }
        }
    }

}
profile
백엔드

0개의 댓글