차곡차곡 성 쌓기
article thumbnail

1. 문제

 


2. 어떻게 풀까?

MST의 비용을 구할 수 있어야 풀 수 있는 문제로 진행되는 라운드 동안 하나씩 가중치가 낮은 간선을 제거하면서 MST의 비용을 구하는 문제이다.

 

잊고 있던 MST 비용 구하는 개념을 다시 복습해보자

  1. Edge 간선을 우선순위 큐에 모두 삽입한다
  2.  가중치가 낮은(또는 높은)순으로 우선순위 큐에서 빼낸다
  3. Edge를 이루는 두 정점을 이을 시 싸이클이 형성되는지 확인한다 (find 연산)
  4. 싸이클이 형성되지 않으면 해당 Edge를 MST를 이루는 간선으로 추가한다.
  5. 간선의 개수가 N-1개가 되면 비용을 리턴한다. N-1개가 되지 못하면 MST 그래프를 만들 수 없다

 

먼저 MST를 구하는 코드를 짠다.

public static int MST(int k, PriorityQueue<Edge> pq){
    int count = 0;
    int sum = 0;

    // parent 배열 자기 자신으로 초기화
    for (int i = 0; i < N+1; i++) {
        parent[i] = i;
    }

    // k개만큼 큐에서 빼주기
    for (int i = 0; i < k; i++)
        pq.poll();

    while(!pq.isEmpty()){
        Edge cur = pq.poll();

        // 같은 그룹에 속하는지 확인
        int a = find(cur.a);
        int b = find(cur.b);

        if(a!=b){
            count++;
            sum += cur.w;   // MST를 이루는 비용 증가

            // 그룹 연결
            parent[b] = a;
        }
    }
    return count == N-1? sum : 0;
}

 

하지만 라운드마다 MST를 형성할 수 있는지 다시 확인해야한다. 이때 고민이 되었다. 우선순위 큐를 어떻게 재활용할 수 있을까....

 

그냥 간선정보를 입력 받을 때 Edge를 저장하는 List를 만들어서 저장하고 `MST()`를 호출할 때마다 새로운 Que를 만들어 List에 들어있는 간선들을 넣어줬다. 이렇게 하고 정답이 되긴했지만 맘에 안들어서 다른 사람들의 코드를 찾아봤다가 새로운 사실을 알았다

 

아래와 같이 `PriorityQueue`를 생성할 때 데이터를 담아둔 우선순위 큐를 넣어주면 안에 들어있는 데이터와 사이즈를 그대로 복사하여 새로운 큐를 만들어준다! 굳이 새로운 큐를 만들고, for문 통해 데이터를 하나하나 넣어주지 않아도 된다😆

 MST(k, new PriorityQueue<>(que));
public static int MST(int k, PriorityQueue<Edge> pq){
    int count = 0;
    int sum = 0;

    // parent 배열 자기 자신으로 초기화
    for (int i = 0; i < N+1; i++) {
        parent[i] = i;
    }
	... 생략
}

 

위의 방식을 사용하여 완성된 코드를 아래와 같다.

 

전체 코드

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.List;
import java.util.PriorityQueue;
import java.util.StringTokenizer;

public class Main {

    public static int N, M, K;
    public static PriorityQueue<Edge> que;
    public static int [] parent;

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

        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

        StringTokenizer st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());   // 그래프 정점의 개수
        M = Integer.parseInt(st.nextToken());   // 그래프 간선의 개수
        K = Integer.parseInt(st.nextToken());   // 턴의 수
        parent = new int[1001];

        // 간선 정보 입력
        que = new PriorityQueue<>();
        for (int i = 1; i <= M; i++) {
            st = new StringTokenizer(br.readLine());
            int a = Integer.parseInt(st.nextToken());
            int b = Integer.parseInt(st.nextToken());

            que.add(new Edge(a, b, i));
        }

        boolean isEnd = false;
        for (int k = 0; k < K; k++) {
            if (isEnd) { // 앞 라운드에서 0이 나왔으면
                bw.write("0 ");
                continue;
            }

            int sum = MST(k, new PriorityQueue<>(que));
            if (sum == 0)
                isEnd = true;
            bw.write(sum + " ");
        }
        bw.flush();
    }

    public static int MST(int k, PriorityQueue<Edge> pq){
        int count = 0;
        int sum = 0;

        // parent 배열 자기 자신으로 초기화
        for (int i = 0; i < N+1; i++) {
            parent[i] = i;
        }

        // k개만큼 큐에서 빼주기
        for (int i = 0; i < k; i++)
            pq.poll();

        while(!pq.isEmpty()){
            Edge cur = pq.poll();

            // 같은 그룹에 속하는지 확인
            int a = find(cur.a);
            int b = find(cur.b);

            if(a!=b){
                count++;
                sum += cur.w;   // MST를 이루는 비용 증가

                // 그룹 연결
                parent[b] = a;
            }
        }
        return count == N-1? sum : 0;
    }

    public static int find(int a){
        if(parent[a] == a)
            return a;

        return find(parent[a]);
    }

}
class Edge implements Comparable<Edge>{
    int a;
    int b;
    int w;

    public Edge(int a, int b, int w) {
        this.a = a;
        this.b = b;
        this.w = w;
    }

    @Override
    public int compareTo(Edge o) {
        // 가중치가 낮은 것을 우선순위로
        return this.w - o.w;
    }
}

728x90
profile

차곡차곡 성 쌓기

@nagrang

포스팅이 좋았다면 "좋아요" 해주세요!