자료구조/문제풀이

[백준 JAVA] 1260 DFS와 BFS

휴먼코딩 2024. 8. 13. 13:52

1260 DFS와 BFS

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

문제설명

그래프를 입력받아 DFS(깊이 우선 탐색)와 BFS(너비 우선 탐색)를 수행한다

접근방식

O(N log N + M) 시간복잡도

 

정렬

  • 각 정점의 인접 리스트를 정렬하는 데 O(E log E) 시간이 소요된다. 여기서 E는 각 정점에 연결된 간선 수이다.
  • DFS
    • DFS의 시간복잡도는 O(N + M)이다.
    • 여기서 N은 정점의 수, M은 간선의 수이며, 각 정점과 간선을 각각 한 번씩 방문한다.
  • BFS
    • BFS의 시간복잡도도 O(N + M)이다.
    • 각 정점과 간선을 각각 한 번씩 방문한다.

 

인접 리스트를 사용하여 그래프를 표현하고, DFS와 BFS를 각각 O(N + M) 시간복잡도로 수행하여 결과를 출력한다.

정렬에 드는 추가 시간 O(E log E)를 고려하면 전체 시간복잡도는 O(N log N + M) 이다.

 

문제 조건 분석 과정

 

  • 입력 처리 및 그래프 생성
    • 정점 수(N), 간선 수(M), 시작 정점(V) 입력받는다
    • 정점들을 저장하기 위해 ArrayList를 사용한 인접 리스트를 생성한다.
    • 간선 정보를 읽어들여 그래프의 양방향 간선 정보를 추가한다
  • DFS(깊이 우선 탐색)
    • DFS를 구현하기 위해 Stack을 사용한다
    • 스택에 시작 정점을 넣고, 노드를 하나씩 꺼내어 방문 처리한다
    • 인접 노드들은 작은 번호부터 처리되도록 역순으로 스택에 추가한다
  • BFS(너비 우선 탐색)
    • BFS를 구현하기 위해 Queue를 사용한다
    • 큐에 시작 정점을 넣고, 노드를 하나씩 꺼내어 방문 처리한다
    • 인접 노드들은 큐에 순차적으로 추가한다

 

전체코드

import java.util.*;
import java.io.*;
import java.util.stream.Collectors;

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

        int N = Integer.parseInt(st.nextToken()); //정점 수
        int M = Integer.parseInt(st.nextToken()); //간선 수
        int V = Integer.parseInt(st.nextToken()); //시작 정점

        //그래프를 인접 리스트에 담음
        List<Integer>[] graph = new ArrayList[N + 1];
        for (int i = 1; i <= N; i++) {
            graph[i] = new ArrayList<>();
        }

        //두 정점에 간선 추가
        for (int i = 0; i < M; i++) {
            st = new StringTokenizer(br.readLine());
            int u = Integer.parseInt(st.nextToken());
            int v = Integer.parseInt(st.nextToken());
            graph[u].add(v);
            graph[v].add(u);
        }

        //각 정점의 인접 리스트 정렬
        for (int i = 1; i <= N; i++) {
            //Stack은 후입선출 구조기 때문에 나중에 들어간 노드 (작은 숫자) 가 먼저 처리됨
            Collections.sort(graph[i]); //오름차순으로 정렬
        }

        //DFS visited 배열
        boolean[] visited = new boolean[N + 1];
        List<Integer> dfsResult = new ArrayList<>();
        dfs(graph, V, visited, dfsResult);

        //BFS 결과 배열
        List<Integer> bfsResult = new ArrayList<>();
        bfs(graph, V, bfsResult);

        //DFS 결과
        System.out.println(dfsResult.stream().map(String::valueOf).collect(Collectors.joining(" ")));
        //BFS 결과
        System.out.println(bfsResult.stream().map(String::valueOf).collect(Collectors.joining(" ")));
    }

    private static void dfs(List<Integer>[] graph, int start, boolean[] visited, List<Integer> result) {
        //Stack을 사용하여 DFS 수행
        Stack<Integer> stack = new Stack<>();
        stack.push(start);

        while (!stack.isEmpty()) {
            int node = stack.pop();
            //노드가 아직 방문하지 않았을 경우
            if (!visited[node]) {
                visited[node] = true; //방문처리
                result.add(node);
                //인접 노드 스택 추가 (역순으로 추가 = 작은 번호 먼저 탐색)
                for (int i = graph[node].size() - 1; i >= 0; i--) {
                    int neighbor = graph[node].get(i);
                    if (!visited[neighbor]) {
                        stack.push(neighbor);
                    }
                }
            }
        }
    }

    private static void bfs(List<Integer>[] graph, int start, List<Integer> result) {
        boolean[] visited = new boolean[graph.length];
        //큐를 사용하여 BFS 수행
        Queue<Integer> queue = new LinkedList<>();
        queue.add(start);
        visited[start] = true;

        while (!queue.isEmpty()) {
            int node = queue.poll();
            result.add(node);
            //인접 노드들을 큐에 추가
            for (int neighbor : graph[node]) {
                if (!visited[neighbor]) {
                    visited[neighbor] = true;
                    queue.add(neighbor);
                }
            }
        }
    }
}