ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [알고리즘] 프로그래머스 3단계 - 양과 늑대
    카테고리 없음 2024. 4. 23. 16:15

    프로그래머스 문제 링크

    https://school.programmers.co.kr/learn/courses/30/lessons/92343

     

    문제 설명

    양과 늑대가 이진 트리 형식의 배열에 존재한다.

    늑대가 양의 수와 같거나 많은 경우 이동할 수 없고 양의 수가 많아야 한다.

    양의 수가 최대인 경우 몇마리인지 리턴한다.

    초기 루트 노드는 양으로 시작한다.

    info에는 양인지 늑대인지 여부가 0과 1로 구성되어있고 edges에는 각 노드간에 연결된 정보와 info에 해당되는 양인지 늑대인지 여부가 결정된다.

     

    예시

     

    info
    [0,0,1,1,1,0,1,0,1,0,1,1]

    edges
    [[0,1],[1,2],[1,4],[0,8],[8,7],[9,10],[9,11],[4,3],[6,5],[4,6],[8,9]]

    result
    5

    import java.util.*;
    
    public class Main {
    
        private static ArrayList<Integer>[] tree;
    
        public static void main(String[] args) {
            System.out.println(solution(new int[]{0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0},new int[][]{{0,1},{0,2},{1,3},{1,4},{2,5},{2,6},{3,7},{4,8},{6,9},{9,10}}));
        }
    
        public static int solution(int[] info, int[][] edges) {
            buildTree(info, edges);
    
            int answer = 0;
    
            ArrayDeque<Info> queue = new ArrayDeque<>();
            queue.add(new Info(0, 1, 0, new HashSet<>()));
    
            while (!queue.isEmpty()) {
                Info now = queue.poll();
    
                answer = Math.max(answer, now.sheep);
    
                // 맨처음 노드가 0번일때는 형제노드가 없어서 아래 addAll 함수 호출시 하위 노드만 포함되게 되지만
                // 한번 하위 노드를 돌고 형제 노드가 있다면 포함 시킨다.
                // 즉 이전에 있던 형제 노드와 현재 노드에 연결된 하위 노드 합쳐지는 배열이다.
                now.visited.addAll(tree[now.node]);
    
                // 형제 노드 + 하위 노드를 하나씩 꺼내서 늑대인지 양인지 판별 후 수를 비교 하여 조건에 따라서 큐에 담는다.
                for (int next : now.visited) {
                    // 여기가 중요한 부분인데 현재 노드의 정보만 제거 하고 연결된 모든 노드 정보를 새로 생성될 큐에 추가한다.
                    HashSet<Integer> set = new HashSet<>(now.visited);
                    set.remove(next);
    
                    // 양인지 늑대인지 판별
                    // 책에서는 중첩 if문으로 구성되었지만 문제에서 기본적으로 0아니면 1만 확실히 주기 때문에 다음과 같이 연산횟수를 줄일 수 있다.
                    //if (info[next] == 1) {
                    //    if (now.sheep != now.wolf + 1) {
                    //        queue.add(new Info(next, now.sheep, now.wolf + 1, set));
                    //    }
                    //} else {
                    //    queue.add(new Info(next, now.sheep + 1, now.wolf, set));
                    //}
                    
                    if (info[next] == 0) {
                        queue.add(new Info(next, now.sheep + 1, now.wolf, set));
                        // 양보다 숫자가 적어야 늑대를 큐에 담는다.
                    } else if(now.sheep != now.wolf + 1) {
                        queue.add(new Info(next, now.sheep, now.wolf + 1, set));
                    }
                }
            }
            return answer;
        }
    
        private static void buildTree(int[] info, int[][] edges) {
            tree = new ArrayList[info.length];
            // 각 노드에 연결된 하위 노드 목록 넣기 위한 리스트 초기화 작업
            for (int i = 0; i < tree.length; i++) {
                tree[i] = new ArrayList<>();
            }
    
            // 각 노드 별로 연결된 노드 추가 ( 0 노드 부터 하위 노드 추가 하여 연결)
            for (int[] edge : edges) {
                tree[edge[0]].add(edge[1]);
            }
        }
    
        private static class Info {
            int node, sheep, wolf;
            HashSet<Integer> visited;
    
            public Info(int node, int sheep, int wolf, HashSet<Integer> visited) {
                this.node = node;
                this.sheep = sheep;
                this.wolf = wolf;
                this.visited = visited;
            }
        }
    }

     

    풀다가 어려워서 책 풀이를 확인했다. 풀이를 확인해도 foreach문 내부에서 HashSet설정하는 이유를 한참 헤맸는데 트리에 익숙해질 필요가 있겠다.

    댓글

Designed by Tistory.