[백준 16724] 피리 부는 사나이(Java)

최민길(Gale)·2024년 2월 17일
1

알고리즘

목록 보기
171/172

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

이 문제는 유니온 파인드와 dfs를 이용하여 풀 수 있습니다.

문제에서 요구하는 SAFE ZONE은 결국 사이클의 개수가 됩니다. 왜냐하면 각 위치에서 사람들이 이동하는 방향은 정해져있기 때문에 하나의 사이클 중 한 군데를 막으면 사이클 내의 모든 사람들이 접근할 수 있기 때문입니다.

이를 구현하기 위해 dfs와 유니온 파인드를 사용했습니다. 부모 배열의 경우 ixM+j의 형태로 좌측 상단부터 우측 하단 방향으로 0부터 1씩 증가하는 식으로 아이디를 부여했습니다. 이후 방문하지 않은 위치를 하나씩 dfs 탐색하여 그래프에 주어진 방향대로 이동시킵니다. 이 때 유니온 연산을 진행하여 이동 가능한 노드끼리 부모 배열을 같에 맞춰줍니다. 여기서 이미 방문한 노드에 도착했을 때 부모 배열값이 같다면 같은 사이클로 간주하여 카운트를 증가시켜줍니다.

다음은 코드입니다.

import java.util.*;
import java.io.*;

class Main{
    static int N,M;
    static Map<Character,Integer> dy = new HashMap<>(), dx = new HashMap<>();
    static char[][] graph;
    static int[][] parent;
    static boolean[][] check;
    static int res = 0;

    public static void main(String[] args) throws Exception{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());

        graph = new char[N][M];
        for(int i=0;i<N;i++){
            String str = br.readLine();
            for(int j=0;j<M;j++) graph[i][j] = str.charAt(j);
        }

        parent = new int[N][M];
        for(int i=0;i<N;i++){
            for(int j=0;j<M;j++){
                parent[i][j] = i*M+j;
            }
        }

        dy.put('D',1);
        dy.put('U',-1);
        dy.put('L',0);
        dy.put('R',0);

        dx.put('D',0);
        dx.put('U',0);
        dx.put('L',-1);
        dx.put('R',1);

        check = new boolean[N][M];
        for(int i=0;i<N;i++){
            for(int j=0;j<M;j++){
                if(!check[i][j]) dfs(i,j);
            }
        }

        System.out.println(res);
    }

    static void dfs(int y, int x){
        check[y][x] = true;

        int ny = y + dy.get(graph[y][x]);
        int nx = x + dx.get(graph[y][x]);
        if(ny<0 || ny>=N || nx<0 || nx>=M) return;

        if(!check[ny][nx]){
            union(y,x,ny,nx);
            dfs(ny,nx);
        }
        else{
            if(parent[y][x] == parent[ny][nx]) res++;
        }
    }

    static void union(int sy, int sx, int ey, int ex){
        int s = find(sy,sx);
        int e = find(ey,ex);

        if(s!=e) parent[ey][ex] = s;
    }

    static int find(int y, int x){
        if(parent[y][x] == y*M+x) return parent[y][x];
        else{
            int ny = parent[y][x]/M;
            int nx = parent[y][x]%M;
            return parent[y][x] = find(ny,nx);
        }
    }
}

profile
저는 상황에 맞는 최적의 솔루션을 깊고 정확한 개념의 이해를 통한 다양한 방식으로 해결해오면서 지난 3년 동안 신규 서비스를 20만 회원 서비스로 성장시킨 Software Developer 최민길입니다.

0개의 댓글

관련 채용 정보