[BOJ] 16932: 모양 만들기 (JAVA)

2024. 4. 26. 16:53·Algorithm/BFS & DFS

문제

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

 

여담

시간 초과가 진짜 많이 발생했다. 오랜만에 골드 BFS 문제를 푸니까 좀 어지럽다. 계속 쉬운 문제만 푸려고 하는 습관을 버려야지 진짜..

 

암튼 처음에는 map[i][j] 값이 0일 때마다 BFS 탐색을 수행하면 되겠다고 생각했다. 그치만 위와 같이 시간 초과가 발생했다. 시간을 줄일 수 있는 방법으로 고쳐나갔는데도 계속 시간 초과가 발생해서 결국 다른 분의 아이디어를 참고했다. 

 

항상 문제를 풀 때 시간 초과를 고려해서 푸는 습관을 들이도록 노력해야지..!

 

풀이

위에서 언급했듯이, map[i][j]의 값이 0이면 BFS 탐색을 수행해서 모양의 최대 넓이를 구하는 방식을 사용하면 시간 초과가 발생한다. 따라서 다음과 같은 순서대로 문제를 풀면 된다.

  1. 1으로만 구성되고 연결된 그룹 찾기
  2. map[i][j]가 0인 곳에서 상하좌우에 그룹이 존재하는지 확인하기
  3. 그룹이 존재한다면 해당 그룹의 넓이(= 연결된 칸의 수)를 더하기

 

이때, 각 그룹을 구별해야 해당 그룹에 포함된 수를 구할 수 있다. 따라서 다음과 같이 그룹에 수를 부여해서 구분할 수 있도록 해야 한다.

 

코드

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

public class Main {
    static int N, M;
    static int[][] map;
    static boolean[][] visited;
    static ArrayList<Pos> zeroList = new ArrayList<>();
    static ArrayList<Pos> oneList = new ArrayList<>();
    static HashMap<Integer, Integer> group = new HashMap<>(); // 그룹 번호, 그룹의 크기
    static int[] dx = {1, -1, 0, 0};
    static int[] dy = {0, 0, 1, -1};

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine(), " ");
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        map = new int[N][M];
        visited = new boolean[N][M];
        for (int i = 0; i < N; i++) {
            st = new StringTokenizer(br.readLine(), " ");
            for (int j = 0; j < M; j++) {
                map[i][j] = Integer.parseInt(st.nextToken());
                if (map[i][j] == 0) zeroList.add(new Pos(i, j)); // 칸에 들어있는 수가 0이면 따로 저장하기
                else oneList.add(new Pos(i, j));
            }
        }

        // 그룹 찾기
        int groupNum = 1;
        for (Pos pos : oneList) {
            if (!visited[pos.x][pos.y]) { // map[i][j]가 1인 것들은 이미 방문 처리가 완료됨
                findGroup(pos.x, pos.y, groupNum++);
            }
        }

        // 그룹 연결하기
        int maxArea = 0;
        for (Pos pos : zeroList) {
            maxArea = Math.max(maxArea, linkedGroup(pos.x, pos.y));
        }
        System.out.println(maxArea);
    }

    static void findGroup(int x, int y, int groupNum) { // 그룹 찾기
        Queue<Pos> queue = new LinkedList<>();
        queue.offer(new Pos(x, y));
        visited[x][y] = true;

        int area = 0;
        while (!queue.isEmpty()) {
            Pos now = queue.poll();
            map[now.x][now.y] = groupNum;
            area++;

            for (int i = 0; i < 4; i++) {
                int nx = now.x + dx[i];
                int ny = now.y + dy[i];
                if (nx < 0 || ny < 0 || nx >= N || ny >= M || visited[nx][ny] || map[nx][ny] == 0) {
                    continue;
                }

                queue.offer(new Pos(nx, ny));
                visited[nx][ny] = true;
            }
        }
        group.put(groupNum, area);
    }

    static int linkedGroup(int x, int y) { // map[i][j]의 값을 0에서 1로 변경한 후, 그룹과 연결하기
        HashSet<Integer> checkGroup = new HashSet<>();
        int area = 1;
        for (int i = 0; i < 4; i++) { // 현재 위치를 기준으로 네 방향 중에 그룹이 있는지만 찾으면 됨!
            int nx = x + dx[i];
            int ny = y + dy[i];
            if (nx < 0 || ny < 0 || nx >= N || ny >= M || map[nx][ny] == 0) {
                continue;
            }

            int groupNum = map[nx][ny];
            if (!checkGroup.contains(groupNum)) {
                area += group.get(groupNum);
                checkGroup.add(groupNum);
            }
        }
        return area;
    }

    static class Pos {
        int x;
        int y;

        public Pos(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }
}

참고

https://suhyeokeee.tistory.com/75

 

'Algorithm > BFS & DFS' 카테고리의 다른 글

[BOJ] 문제 풀이 모음집 - BFS/DFS (JAVA)  (0) 2024.06.17
[BOJ] 2638: 치즈 (JAVA)  (0) 2024.05.01
[BOJ] 7569: 토마토 (JAVA)  (0) 2024.03.20
[BOJ] 17836: 공주님을 구해라! (JAVA)  (0) 2024.03.20
[BOJ] 7576: 토마토 (JAVA)  (0) 2024.03.20
'Algorithm/BFS & DFS' 카테고리의 다른 글
  • [BOJ] 문제 풀이 모음집 - BFS/DFS (JAVA)
  • [BOJ] 2638: 치즈 (JAVA)
  • [BOJ] 7569: 토마토 (JAVA)
  • [BOJ] 17836: 공주님을 구해라! (JAVA)
hjin28
hjin28
  • hjin28
    끄적이는 기록장
    hjin28
  • 전체
    오늘
    어제
  • 블로그 메뉴

    • 홈
    • 태그
    • GitHub
    • 이전 블로그
    • 분류 전체보기
      • TIL
      • Frontend
      • Backend
      • Infra
      • Java
        • 이것이 자바다
      • CS
        • 컴퓨터구조
        • 운영체제
        • 네트워크
        • 데이터베이스
      • Algorithm
        • 자료구조
        • 시뮬레이션
        • 완전탐색
        • BFS & DFS
        • DP
        • 그리디
        • 최단경로
        • 유니온파인드
        • 위상정렬
        • 정렬
        • SQL
      • ETC
  • 최근 글

  • 태그

    Spring
    투포인터
    다이나믹프로그래밍
    DFS
    Programmers
    vue
    DP
    CS
    덱
    SWEA
    BFS
    완전탐색
    유니온파인드
    websocket
    백트래킹
    자바
    JWT
    자료구조
    구현
    java
    til
    컴퓨터구조
    springsecurity
    최단경로
    ec2
    백준
    그리디
    SQL
    위상정렬
    비트마스킹
  • hELLO· Designed By정상우.v4.10.1
hjin28
[BOJ] 16932: 모양 만들기 (JAVA)
상단으로

티스토리툴바