티스토리 뷰

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

 

14502번: 연구소

인체에 치명적인 바이러스를 연구하던 연구소에서 바이러스가 유출되었다. 다행히 바이러스는 아직 퍼지지 않았고, 바이러스의 확산을 막기 위해서 연구소에 벽을 세우려고 한다. 연구소는 크

www.acmicpc.net

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

public class Main {

    public static class Node {
        int y, x;
        public Node(int y, int x) {
            this.y = y;
            this.x = x;
        }
    }

    static int N, M, max, max_area = 0;
    static int[][] map;
    static boolean[][] visited;
    static Node[] walls = new Node[3];
    static List<Node> virus = new ArrayList<>();
    static int[] arr = new int[3];
    static int[] dx = {1, 0, -1, 0};
    static int[] dy = {0, 1, 0, -1};

    // 벽 위치 초기화
    public static void init_wall() {
        int cnt = 0;
        for(int j = 0; j < N; j++) {
            for(int i = 0; i < M; i++) {
                if(map[j][i] == 0) {
                    walls[cnt++] = new Node(j, i);
                    map[j][i] = 3; // 임의로 지은 벽은 3으로 표시
                    if(cnt == 3) {
                        return;
                    }
                }
            }
        }
    }
    
    // 총 이동가능 횟수.
    public static int calc_time() {
        int x = walls[2].x;
        int y = walls[2].y;
        int cnt = 0;
        while(true) {
            x += 1;
            if(x >= M) {
                x = 0;
                y += 1;
                if(y >= N) {
                    return cnt;
                }
            }
            if(map[y][x] == 0) {
                cnt += 1;
            }
        }
    }

    // 벽 움직이기
    public static void move_walls(int cnt) {
        int x = walls[cnt].x;
        int y = walls[cnt].y;
        while(map[y][x] != 0) {
            x += 1;
            if(x >= M) {
                x = 0;
                y += 1;
                if(y >= N) {
                    return;
                }
            }
        }
        map[walls[cnt].y][walls[cnt].x] = 0; // 기존 벽 부수고
        walls[cnt] = new Node(y, x);
        map[y][x] = 3; // 새로 이동함.
    }

    // 바이러스 퍼트리기
    public static void bfs(Node start) {

        Queue<Node> queue = new LinkedList<>();
        queue.add(start);
        visited[start.y][start.x] = true;

        while(!queue.isEmpty()) {
            Node e = queue.poll();
            visited[e.y][e.x] = true;
            for (int i = 0; i < 4; i++) {
                int nx = dx[i] + e.x;
                int ny = dy[i] + e.y;
                if(nx < 0 || ny < 0 || nx >= M || ny >= N) {
                    continue; // OutOfBounds
                }
                if(map[ny][nx] != 0) {
                    continue; // 벽은 지나갈 수 없음. + 바이러스끼리 못뚫음
                }
                if(visited[ny][nx]) {
                    continue; // 이미 지나간데도 갈 수 없음
                }
                queue.add(new Node(ny, nx));
                visited[ny][nx] = true;
            }
        }
    }

    // 총 안전영역 세기
    public static int calc_safeArea() {
        int cnt = 0;
        for(int j = 0; j < N; j++) {
            for(int i = 0; i < M; i++) {
                if(!visited[j][i] && map[j][i] == 0) {
                    cnt++;
                }
            }
        }
        return cnt;
    }

    // 벽 위치 정하기
    public static void backtracking(int depth) {
        if(depth == 3) {
            // 벽 움직이고
            for(int i = 2; i >= 0; i--) {
                for(int j = 0; j < arr[i]; j++) {
                    move_walls(i);
                }
            }
            // BFS 찍고
            visited = new boolean[N][M];
            for (Node node : virus) {
                bfs(node);
            }
            max_area =  Math.max(max_area, calc_safeArea());
            // 다음을 위해 벽 초기화
            for(int i = 0; i < 3; i++) {
                map[walls[i].y][walls[i].x] = 0;
            }
            init_wall();
            return;
        }
        for(int i = 0; i <= max; i++) {
            arr[depth] = i;
            backtracking(depth + 1);
        }
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        StringTokenizer stk = new StringTokenizer(br.readLine());
        N = Integer.parseInt(stk.nextToken());
        M = Integer.parseInt(stk.nextToken());
        map = new int[N][M];

        for(int i = 0; i < N; i++) {
            stk = new StringTokenizer(br.readLine());
            for(int j = 0; j < M; j++) {
                map[i][j] = Integer.parseInt(stk.nextToken());
                if(map[i][j] == 2) {
                    virus.add(new Node(i, j));
                }
            }
        }
        init_wall();
        max = calc_time();
        backtracking(0);

        bw.write(max_area + "\n");
        bw.flush();
        bw.close();
    }
}

 

 

또 어째저째 풀긴 했는데 코드가 역시나 난잡해졌다.

 

딱 보니까 완전탐색 문제라는 느낌이 팍 왔으나, 세개의 벽을 어떻게 세우느냐를 막상 구현하라니까 또 깝깝했다.

 

1. 일단 가능한 첫번째 위치에 벽을 세운다 - init_wall( ) 메소드로 구현

2. 세번째 벽(제일 끝에 위치한 벽)이 배열 끝까지 몇번 이동할 수 있는지를 센다 - calc_time ( ) 메소드로 구현

3. 백트래킹을 이용해서 가능한 모든 경우의 수를 생성한다

[0, 0, 0]부터 시작해서 [max, max, max] 까지

 

4. 각 경우의 수마다 bfs를 사용해서 바이러스를 퍼트린다 - bfs( ) 메소드로 구현

5. 해당 경우에서 안전영역의 크기를 구한다 - calc_safeArea( ) 메소드로 구현

 

 

-----

 

아 뭔가 난잡하다.

조금 더 머리만 쓰면 간결하게 구현할 수 있을 것 같은데.

 

 

다른사람 코드보고 공부좀 할 것.

 

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함