All :L

[BOJ/Java] 치즈 (2638) 본문

CODING/BOJ

[BOJ/Java] 치즈 (2638)

ofijwe 2024. 8. 29. 15:10
반응형

치즈 (2638)

1. 문제 분석

문제 개요

  • N x M 크기의 종이에서 치즈가 놓여있으며, 치즈는 1로 표시된다. 치즈의 가장자리는 공기와 접촉할 때 녹게 되며, 두 면 이상이 공기와 접촉한 치즈는 한 번의 과정에서 모두 녹는다. 치즈가 모두 녹을 때까지의 시간을 계산하는 문제이다.

입력 형식

  • 첫 줄에는 종이의 크기 N (세로)과 M (가로)가 주어진다.
  • 그다음 N개의 줄에 걸쳐서 각 칸에 치즈가 있는지 없는지에 대한 정보가 주어진다. 0은 공기, 1은 치즈를 나타낸다.

출력 형식

  • 치즈가 모두 녹는 데 걸리는 시간을 출력한다.

2. 알고리즘 종류

  • 이 문제는 DFS(깊이 우선 탐색)시뮬레이션을 사용하는 문제이다. DFS를 사용해 치즈의 외부 공기를 탐색하고, 시뮬레이션을 통해 치즈가 녹는 과정을 반복적으로 수행해 해결한다.

3. 주요 부분 및 코드 작성 방법

1. DFS 사용

  • DFS를 통해 치즈의 외부 공기를 탐색하고, 내부 공기를 확인하여 치즈가 두 면 이상 공기와 접촉했는지 판단한다.

2. 치즈 녹이기 시뮬레이션

  • 치즈가 녹는 과정을 반복하여 모든 치즈가 녹을 때까지 시뮬레이션을 수행한다.

4. 코드 설명

(1) 메인 함수 (main)

  • 입력 처리

      BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); // 입력을 받기 위한 BufferedReader 객체 생성
      StringTokenizer st = new StringTokenizer(br.readLine()); // 한 줄의 입력을 공백을 기준으로 나누어 처리
    
      N = Integer.parseInt(st.nextToken()); // 종이의 세로 크기 입력
      M = Integer.parseInt(st.nextToken()); // 종이의 가로 크기 입력
    
      paper = new int[N][M]; // 종이의 크기만큼 2차원 배열 초기화
    • BufferedReaderStringTokenizer를 사용해 입력을 처리한다.
  • 종이 상태 초기화 및 입력된 위치 저장

      for(int i = 0; i < N; i++) {
          st = new StringTokenizer(br.readLine()); // 한 줄의 입력을 공백을 기준으로 나누어 처리
          for(int j = 0; j < M; j++) {
              paper[i][j] = Integer.parseInt(st.nextToken()); // 치즈 및 공기 정보를 2차원 배열에 저장
          }
      }
    • 입력받은 치즈와 공기 정보를 2차원 배열 paper에 저장한다.
  • 치즈 녹이기 시뮬레이션 및 결과 출력

      boolean flag = true; // 치즈가 모두 녹았는지 여부를 확인하는 변수
      int cnt = 0; // 치즈가 녹는 데 걸리는 시간을 저장하는 변수
    
      while (flag) {
          checked = new boolean[N][M]; // 내부 공간 확인을 위한 boolean 배열 초기화
          dfs(0, 0); // 치즈의 외부 공간을 파악하기 위한 DFS 수행
    
          for(int i = 0; i < N; i++) { // 모든 위치를 순회하며
              for(int j = 0; j < M; j++) {
                  if(paper[i][j] == 1) counting(i, j); // 치즈가 있는 위치에서 공기와의 접촉 면 수를 계산
              }
          }
    
          int cheese = 0; // 녹은 치즈의 개수를 저장하는 변수
          for(int i = 0; i < N; i++) {
              for(int j = 0; j < M; j++) {
                  if(paper[i][j] > 1) { // 두 면 이상 공기와 접촉한 치즈라면
                      paper[i][j] = 0; // 해당 치즈를 녹임
                      cheese++; // 녹은 치즈 개수 증가
                  }
              }
          }
    
          if(cheese == 0) { // 녹을 치즈가 더 이상 없다면 시뮬레이션 종료
              flag = false;
              break;
          }
    
          cnt++; // 치즈가 모두 녹지 않았다면 시간을 증가시키고 다음 반복 수행
      }
      System.out.println(cnt); // 최종 결과 출력
    • while 루프를 통해 치즈가 모두 녹을 때까지 반복적으로 DFS와 시뮬레이션을 수행하며, 최종적으로 치즈가 모두 녹는 데 걸리는 시간을 출력한다.

(2) 공기와 접촉한 치즈 판단 함수 (counting)

  • 공기 접촉 면 계산

      int cnt = 0; // 공기와 접촉한 면의 수를 저장하는 변수
    
      for (int i = 0; i < 4; i++) { // 4방향으로 탐색 (상하좌우)
          int nr = r + dr[i]; // 새로운 행 위치
          int nc = c + dc[i]; // 새로운 열 위치
    
          if(nr < 0 || nc < 0 || nr >= N || nc >= M) continue; // 지도를 벗어난 경우 건너뜀
          if(paper[nr][nc] == 0 && checked[nr][nc]) cnt++; // 공기와 접촉한 면이라면 cnt 증가
      }
    
      if(cnt >= 2) paper[r][c] = cnt; // 두 면 이상이 공기와 접촉한 경우 해당 위치를 녹일 준비
    • 치즈가 공기와 접촉한 면의 수를 계산하여, 두 면 이상이 공기와 접촉한 경우 녹도록 설정한다.

(3) 치즈 외부 공간 파악 함수 (dfs)

  • DFS를 통한 외부 공기 탐색

      checked[r][c] = true; // 현재 위치를 방문 처리
    
      for (int i = 0; i < 4; i++) { // 4방향으로 탐색 (상하좌우)
          int nr = r + dr[i]; // 새로운 행 위치
          int nc = c + dc[i]; // 새로운 열 위치
    
          if(nr < 0 || nc < 0 || nr >= N || nc >= M || checked[nr][nc]) continue; // 지도를 벗어나거나 이미 방문한 경우 건너뜀
          if(paper[nr][nc] == 0) { // 외부 공기라면
              dfs(nr, nc); // 재귀 호출을 통해 탐색 계속
              checked[nr][nc] = true; // 탐색 완료 후 방문 처리
          }
      }
    • 현재 위치에서 4방향으로 인접한 칸들을 탐색하며, 범위 내에 있고 방문하지 않았으며 외부 공기라면 DFS를 재귀 호출해 탐색을 이어간다.

5. 전체 코드

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

public class BOJ2638 {
    static int N, M;
    static int[][] paper;
    static boolean[][] checked; // 치즈 내부 공간 체크
    static int[] dr = {-1, 1, 0, 0}; // 방향 배열: 상하좌우
    static int[] dc = {0, 0, -1, 1}; // 방향 배열: 상하좌우

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); // 입력을 받기 위한 BufferedReader 객체 생성
        StringTokenizer st = new StringTokenizer(br.readLine()); // 한 줄의 입력을 공백을 기준으로 나누어 처리

        N = Integer.parseInt(st.nextToken()); // 종이의 세로 크기 입력
        M = Integer.parseInt(st.nextToken()); // 종이의 가로 크기 입력

        paper = new int[N][M]; // 종이의 크기만큼 2차원 배열 초기화

        for(int i = 0; i < N; i++) {
            st = new StringTokenizer(br.readLine()); // 한 줄의 입력을 공백을 기준으로 나누어 처리
            for(int j = 0; j < M; j++) {
                paper[i][j] = Integer.parseInt(st.nextToken()); // 치즈 및 공기 정보를 2차원 배열에 저장
            }
        }

        boolean flag = true; // 치즈가 모두 녹았는지 여부를 확인하는 변수
        int cnt = 0; // 치즈가 녹는 데 걸리는 시간을 저장

하는 변수

        while (flag) {
            checked = new boolean[N][M]; // 내부 공간 확인을 위한 boolean 배열 초기화
            dfs(0, 0); // 치즈의 외부 공간을 파악하기 위한 DFS 수행

            for(int i = 0; i < N; i++) { // 모든 위치를 순회하며
                for(int j = 0; j < M; j++) {
                    if(paper[i][j] == 1) counting(i, j); // 치즈가 있는 위치에서 공기와의 접촉 면 수를 계산
                }
            }

            int cheese = 0; // 녹은 치즈의 개수를 저장하는 변수
            for(int i = 0; i < N; i++) {
                for(int j = 0; j < M; j++) {
                    if(paper[i][j] > 1) { // 두 면 이상 공기와 접촉한 치즈라면
                        paper[i][j] = 0; // 해당 치즈를 녹임
                        cheese++; // 녹은 치즈 개수 증가
                    }
                }
            }

            if(cheese == 0) { // 녹을 치즈가 더 이상 없다면 시뮬레이션 종료
                flag = false;
                break;
            }

            cnt++; // 치즈가 모두 녹지 않았다면 시간을 증가시키고 다음 반복 수행
        }
        System.out.println(cnt); // 최종 결과 출력
    }

    // 치즈가 공기와 접촉한 면의 수를 계산하는 함수
    public static void counting(int r, int c) {
        int cnt = 0; // 공기와 접촉한 면의 수를 저장하는 변수

        for (int i = 0; i < 4; i++) { // 4방향으로 탐색 (상하좌우)
            int nr = r + dr[i]; // 새로운 행 위치
            int nc = c + dc[i]; // 새로운 열 위치

            if(nr < 0 || nc < 0 || nr >= N || nc >= M) continue; // 지도를 벗어난 경우 건너뜀
            if(paper[nr][nc] == 0 && checked[nr][nc]) cnt++; // 공기와 접촉한 면이라면 cnt 증가
        }

        if(cnt >= 2) paper[r][c] = cnt; // 두 면 이상이 공기와 접촉한 경우 해당 위치를 녹일 준비
    }

    // 치즈 외부 공간을 파악하는 DFS 함수
    public static void dfs(int r, int c) {
        checked[r][c] = true; // 현재 위치를 방문 처리

        for (int i = 0; i < 4; i++) { // 4방향으로 탐색 (상하좌우)
            int nr = r + dr[i]; // 새로운 행 위치
            int nc = c + dc[i]; // 새로운 열 위치

            if(nr < 0 || nc < 0 || nr >= N || nc >= M || checked[nr][nc]) continue; // 지도를 벗어나거나 이미 방문한 경우 건너뜀
            if(paper[nr][nc] == 0) { // 외부 공기라면
                dfs(nr, nc); // 재귀 호출을 통해 탐색 계속
                checked[nr][nc] = true; // 탐색 완료 후 방문 처리
            }
        }
    }
}
반응형

'CODING > BOJ' 카테고리의 다른 글

[BOJ/Java] 농장 관리 (1245)  (0) 2024.08.29
[BOJ/Java] 양 한마리... 양 두마리... (11123)  (0) 2024.08.29
[BOJ/Java] 섬의 개수 (4963)  (0) 2024.08.28
[BOJ/Java] 음식물 피하기 (1713)  (0) 2024.08.28
[BOJ/Java] 듣보잡 (1764)  (0) 2024.08.28
Comments