ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Java] 백준 9466 텀 프로젝트
    Programming/Algorithm 2021. 2. 22. 10:14

     

    문제

    학생의 수 N과 1부터 N까지의 학생이 팀을 이루고 싶은 학생 번호가 주어진다.

    어떤 팀에도 속하지 않는 학생의 수를 계산해라.

    - 학생 수 (2 <= N <= 100,000)

     

     

    1. Deque을 이용한 풀이

    - 각 학생이 선택한 학생번호를 담을 int배열 students와 확인 여부를 담을 boolean배열 visited를 둔다.

    - for문을 돌며 각 학생들이 팀을 이룰 수 있는지 확인한다.

       - 아직 방문하지 않은 학생이라면 Deque에 추가

       - 현재 학생(curr)이 가리키는 다음 학생(next)을 검사

          - 방문하지 않았다면 Deque에 추가

          - 이미 방문했다면 현재 Deque에 있는 학생들로 팀을 이룰 수 있는지 검사

              - Deque의 첫번째 학생(queue.peekFirst())과 다음 학생번호(next)가 일치하는지 검사

              - 일치하지 않는다면 첫번째 학생을 Deque에서 제거하여 Deque가 빌 때까지 검사

     

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.util.Deque;
    import java.util.LinkedList;
    import java.util.StringTokenizer;
    
    public class b9466 {
    
        public static void main(String[] args) throws IOException {
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            StringBuilder sb = new StringBuilder();
            int T = Integer.parseInt(br.readLine());
    
            while (T-- > 0) {
                int N = Integer.parseInt(br.readLine());
                int[] students = new int[N];
                boolean[] visited = new boolean[N];
                int total = N;
    
                StringTokenizer st = new StringTokenizer(br.readLine());
                for (int i = 0; i < N; i++) {
                    students[i] = Integer.parseInt(st.nextToken()) - 1;
                }
    
                for (int i = 0; i < N; i++) {
                    if (visited[i]) continue;
    
                    int cnt = 0;
                    Deque<Integer> queue = new LinkedList<>();
                    queue.add(i);
                    visited[i] = true;
    
                    loop:
                    while (!queue.isEmpty()) {
                        int curr = queue.peekLast();
                        int next = students[curr];
                        if (!visited[next]) {
                            // 방문 안했으면
                            queue.add(next);
                            visited[next] = true;
                        }
                        else{
                            // 방문했으면
                            while(!queue.isEmpty()){
                                // front와 비교
                                if (queue.peekFirst() == next) {
                                    cnt = queue.size();
                                    break loop;
                                }
                                queue.poll();
                            }// while
                        }
                    }// while
    
                    if (cnt > 0)
                        total -= cnt;
                }// for
    
                sb.append(total).append("\n");
            }
    
            System.out.println(sb);
        }
    }
    

     

     

    2. DFS 풀이

    - 각 학생이 선택한 학생번호를 담을 int배열 students, 방문 확인여부를 담을 boolean배열 visited, 덧셈 확인여부를 담을 boolean배열 checked를 둔다.

    - for문을 돌며 각 학생들이 팀을 이룰 수 있는지 확인한다.

       - dfs(학생번호)를 재귀적으로 호출한다.

       - 현재 학생이 아직 방문하지 않은 상태라면 visited[학생번호]를 true로 변경하고 다음학생(next)의 방문여부를 검사한다.

       - 다음학생(next)을 아직 방문하지 않은 상태라면 dfs(next)를 호출한다.

       - 다음학생(next)을 이미 방문한 상태라면 팀을 이룰 수 있는지를 검사한다.

       - 검사한 후에 현재 학생의 checked 여부를 true로 변경한다.(호출한 쪽으로 뒤돌아가면, if(!checked[next])를 이용하여 이전 함수에서 체크했는지를 확인)

     

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.util.StringTokenizer;
    
    public class b9466 {
        static int total, N;
        static int[] students;
        static boolean[] visited, checked;
    
        public static void main(String[] args) throws IOException {
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            StringBuilder sb = new StringBuilder();
            int T = Integer.parseInt(br.readLine());
    
            while (T-- > 0) {
                total = 0;
                N = Integer.parseInt(br.readLine());
                students = new int[N];
                visited = new boolean[N];
                checked = new boolean[N];
    
                StringTokenizer st = new StringTokenizer(br.readLine());
                for (int i = 0; i < N; i++) {
                    students[i] = Integer.parseInt(st.nextToken()) - 1;
                }
    
                for (int i = 0; i < N; i++) {
                    dfs(i);
                }
    
                sb.append(N - total).append("\n");
            }
    
            System.out.println(sb);
        }
    
        static void dfs(int start) {
            if (visited[start]) return;
    
            visited[start] = true;
            int next = students[start];
    
            if (!visited[next]) {
                dfs(next);
            }
            if (!checked[next]) {
                for (int s = next; s != start; s = students[s]) {
                    total++;
                }
                total++;
            }
    
            checked[start] = true;
        }
    }
    

     

     

    채점 결과

    위(DFS) 아래(Deque)

     

    'Programming > Algorithm' 카테고리의 다른 글

    [Java] 백준 2178 미로 탐색  (0) 2021.02.25
    [Java] 백준 2146 다리만들기  (0) 2021.02.25
    [Java] 백준 7576 토마토  (0) 2021.02.23
    [Java] 백준 4963 섬의 개수  (0) 2021.02.23
    [Java] 백준 2667 단지번호붙이기  (0) 2021.02.23

    댓글

Designed by black7375.