카테고리:

업데이트:

1. 문제

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

알고리즘 분류 : 그래프 이론, 자료 구조, 그래프 탐색, 분리 집합

2. 고민

이번 문제는 “친구의 친구는 친구다” 에서 union-find를 사용하면 될 것이라는 아이디어를 얻었습니다.

추가로, 한정된 돈을 가지고 친구를 얻어야 하므로 친구비를 오름차순으로 정렬해서 Greedy 방식으로

적은 금액의 친구비부터 하나씩 선택하는 방법을 생각했습니다.

3. 설계

[1] 입력 (친구관계 입력 시 union 작업)

[2] 친구비 오름차순 정렬

[3] 적은 친구비부터 하나씩 선택하면서 비용 구하기

[4] 출력

4. 코드

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.util.Arrays;
    import java.util.Comparator;
    import java.util.StringTokenizer;

    public class Main {

        static int student, relationship, havingMoney, cost;    // 학생 수, 관계 수, 가지고 있는 돈, 비용
        static int[][] friendCosts;                             // 친구비
        static int[] parent;                                    // union-find parent
        static boolean[] isFriend;                              // 현재 친구 관계

        // 최상위 부모를 찾는 메서드
        static int find(int x) {
            if(x == parent[x])  return x;

            return parent[x] = find(parent[x]);
        }

        // 두 집합을 합치는 메서드
        static void union(int a, int b) {
            a = find(a);
            b = find(b);

            if(a == b)  return;

            int minValue = Math.min(a, b);
            parent[a] = minValue;
            parent[b] = minValue;
        }

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

            // Input 학생 수, 관계 수, 가지고 있는 돈
            student = Integer.parseInt(st.nextToken());
            relationship = Integer.parseInt(st.nextToken());
            havingMoney = Integer.parseInt(st.nextToken());

            // Initialize
            parent = new int[student+1];
            friendCosts = new int[student][2];
            isFriend = new boolean[student+1];

            // Input 친구비, Initialize union-find parent
            st = new StringTokenizer(br.readLine());
            for(int idx=1; idx<=student; idx++) {
                parent[idx] = idx;
                friendCosts[idx-1][0] = idx;
                friendCosts[idx-1][1] = Integer.parseInt(st.nextToken());
            }

            // Input 친구 관계 -> union 작업
            for(int idx=0; idx<relationship; idx++) {
                st = new StringTokenizer(br.readLine());
                int personA = Integer.parseInt(st.nextToken());
                int personB = Integer.parseInt(st.nextToken());

                union(personA, personB);
            }

            // 친구비를 오름차순으로 정렬
            Arrays.sort(friendCosts, new Comparator<int[]>() {
                @Override
                public int compare(int[] o1, int[] o2) {
                    return o1[1] - o2[1];
                }
            });

            // 적은 친구비부터 하나씩 선택하면서 친구인지 확인 후 비용에 추가
            for(int idx=1; idx<=student; idx++) {
                int person = find(friendCosts[idx-1][0]);

                if(isFriend[person]) continue;

                isFriend[person] = true;
                cost += friendCosts[idx-1][1];

                if(cost > havingMoney)  break;
            }
            
            // 모든 친구를 택하는 비용이
            // 가지고 있는 돈보다 많은 경우 Oh no 출력
            // 가지고 있는 돈으로 충분한 경우 비용 출력
            System.out.println(cost <= havingMoney ? cost : "Oh no");
        }
    }
            
              📕 개인 기록용 블로그입니다.
              😊 오타나 잘못된 정보가 있을 경우 댓글이나 메일로 말씀해주시면 바로 수정하겠습니다! 😊
          

댓글남기기