OJ

[BOJ] 16950 레드 블루 스패닝 트리 2 (JAVA)

P3PP4 2023. 1. 25. 10:00

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

 

16950번: 레드 블루 스패닝 트리 2

첫 줄에는 세 정수 n, m, k가 주어진다. n은 그래프의 정점의 개수 (2 ≤ n ≤ 1,000)이고, m은 간선의 개수, k는 문제에 설명되어 있는 파란색 간선의 개수 (0 ≤ k < n) 이다. 다음 m개 줄에는 간선의 정

www.acmicpc.net

1. 빨간색 간선, 파란색 간선을 따로 저장합니다.

2. 파란색 간선 중 신장 트리를 만들기 위한 필수 간선을 따로 저장합니다.

3. 필수 간선을 우선으로 신장 트리를 만들기 시작하여, 신장 트리의 파란색 간선의 수가 K가 될 때까지 파란색 간선을 추가합니다.

4. 나머지를 빨간색 간선으로 채우면서 신장 트리를 완성합니다.

 

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.StringTokenizer;

public class Main {
    
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StringBuilder sb = new StringBuilder();
    static StringTokenizer st;
    static int N, M, K, redCnt, blueCnt;
    static int[] parent;
    static ArrayList<Line> red, blue, compulsory;

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

        st = new StringTokenizer(br.readLine(), " ");
        N = Integer.parseInt(st.nextToken()); // 정점 수
        M = Integer.parseInt(st.nextToken()); // 간선 수
        K = Integer.parseInt(st.nextToken()); // 파란 간선 수
        red = new ArrayList<>();
        blue = new ArrayList<>();
        compulsory = new ArrayList<>();
        for (int i = 0; i < M; i++) {
            st = new StringTokenizer(br.readLine(), " ");
            char a = st.nextToken().charAt(0);
            int from = Integer.parseInt(st.nextToken());
            int to = Integer.parseInt(st.nextToken());
            if(a == 'R') red.add(new Line(from, to));
            else blue.add(new Line(from, to));
        } // end of input

        // 파란색 간선 수가 K보다 적으면 종료
        if(blue.size() < K) {
            System.out.print(0);
            return;
        }

        make();

        for (Line r : red) {
            if(union(r.from, r.to) && ++redCnt == N - 1) break;
        }
        for (Line b : blue) {
            if(blueCnt + redCnt == N - 1) break;
            if(union(b.from, b.to)) {
                compulsory.add(b);
                blueCnt++;
            }
        }

        // 가망 없으면 종료
        if(K < blueCnt || blueCnt + redCnt < N - 1) {
            System.out.print(0);
            return;
        }

        make();
        redCnt = 0;
        blueCnt = compulsory.size();

        for (Line c : compulsory) {
            union(c.from, c.to);
            sb.append(c.from + " " + c.to + "\n");
        }
        for (Line b : blue) {
            if(blueCnt == K || blueCnt == N - 1) break;
            if(union(b.from, b.to)) {
                sb.append(b.from + " " + b.to + "\n");
                blueCnt++;
            }
        }
        for (Line r : red) {
            if(blueCnt + redCnt == N - 1) break;
            if(union(r.from, r.to)) {
                sb.append(r.from + " " + r.to + "\n");
                redCnt++;
            }
        }

        if(blueCnt != K || blueCnt + redCnt != N - 1) System.out.print(0);
        else System.out.print(sb.toString());

    }

    static boolean union(int a, int b) {

        a = find(a);
        b = find(b);

        if(a == b) return false;

        if(a < b) parent[b] = a;
        else parent[a] = b;

        return true;

    }

    static int find(int a) {

        if(a == parent[a]) return a;

        return parent[a] = find(parent[a]);

    }

    static void make() {

        parent = new int[N + 1];

        for (int i = 1; i <= N; i++) {
            parent[i] = i;
        }

    }

    static class Line {

        int from, to;

        public Line(int from, int to) {
            this.from = from;
            this.to = to;
        }

    }
    
}