Algorithm PS/Baekjoon Online Judge

[BOJ/백준] 2668 숫자고르기 (G5)

kyung.Kh 2024. 7. 23. 18:00

문제

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

풀이

문제를 보면 표는 두 줄로 구성되어 있으며, 첫째 줄에는 1부터 N까지의 숫자가 순서대로, 둘째 줄에는 임의의 1이상 N 이하의 숫자가 들어 있다. 첫째 줄에서 숫자를 선택해서, 선택한 숫자들과 그 아래 둘째 줄의 숫자들이 이루는 집합이 일치해야 한다. 그리고 선택된 숫자들의 개수가 최대가 되어야 한다.

 

각 숫자에서 시작하여 둘째 줄의 숫자를 따라가다가 출발 숫자를 다시 만나면 사이클이 형성된다. 사이클을 찾기 위해 DFS를 사용했다. 각 숫자의 출발점으로 DFS를 수행하여 사이클을 찾아내고, 그 사이클에 속하는 숫자들을 결과 리스트에 추가한다.

DFS 탐색 중에 각 숫자가 여러 번 방문되지 않도록 방문 처리를 하고, 각 탐색이 끝난 후에는 방문 처리를 초기화하여 다른 숫자에 대한 탐색에 영향을 주지 않도록 하였다.

 

DFS로 사이클을 찾아서 푸는 문제는 처음이여서 DFS로 어떻게 접근해야 하는지 방법을 찾는 데 시간이 오래 걸렸다. 

Code

import java.io.*;
import java.util.Collections;
import java.util.LinkedList;

public class Main {

    static int N, num;
    static int[] graph;
    static boolean[] visited;
    static LinkedList<Integer> result;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

        N = Integer.parseInt(br.readLine());
        graph = new int[N + 1];

        for (int i = 1; i <= N; i++) {
            graph[i] = Integer.parseInt(br.readLine());  // i번째 인덱스에 값
        }

        visited = new boolean[N + 1];
        result = new LinkedList<>();

        for (int i = 1; i <= N; i++) {
            visited[i] = true;
            num = i;
            dfs(i);
            visited[i] = false;  // 다른 숫자를 시작점으로하여 다시 dfs를 해야하기 때문에 false 처리
        }
        Collections.sort(result);
        bw.write(result.size() + "\n");
        for (int i = 0; i < result.size(); i++) {
            bw.write(result.get(i) + "\n");
        }
        bw.flush(); bw.close();
    }

    // dfs 로직 : 출발 숫자 -> graph[출발 숫자] -> graph[graph[출발 숫자]]를 반복하다가 출발 숫자를 다시 만나게 되면, 첫째 줄과 둘째 줄의 정수들의 집합이 일치한다고 볼 수 있다.
    static void dfs(int now) {  // 시작 인덱스와 다음 인덱스로 dfs 진행. 다음 노드는 graph[now](graph의 인덱스 i가 현재 노드이고, graph[i]가 다음 노드이므로)
        // 현재 노드의 now 값이 처음 dfs를 시작한 값(num)과 같다면 사이클이 완성된것이므로 result에 추가
        if (graph[now] == num) result.add(num);

        // 다음 노드 검사
        if (!visited[graph[now]]) {  // graph의 현재 노드가 방문하지 않은 곳이라면?
            visited[graph[now]] = true;  // 현재 노드를 방문 처리
            dfs(graph[now]);  // dsf 재귀 호출로 다음 노드를 방문
            visited[graph[now]] = false;  // 재귀 호출 종료 후 방문 처리 해제
        }
    }
}

728x90