BOJ 11967 불켜기

메모리 : 195384 KB

시간 : 704 ms


풀이

문제에서 인접한 상하좌우로만 이동이 가능하에서 BFS나 DFS 탐색이라고 생각했다.

힌트를 보니 방문했던 곳을 다시 방문할 수 있기에, 어떻게 그걸 가능하게 할까 고민했다.

불이 켜진 개수에 따라 다시 이동할 수 있게 해야겠다고 생각해서 방문 배열을 3차원 배열로 만들었다.

한 방에서 여러 개의 스위치가 있을 수 있기 때문에 ArrayList 배열을 이용하여 map을 만들었다.

그 후 각 위치에서 불을 킬 수 있는 방들의 위치가 있을때마다 추가해주었다.

또한 각 방의 불이 켜져있는지 아닌지 boolean 타입 배열을 선언해주었다.

이렇게 해서 방문 점검 배열, 스위치를 저장하고 있는 배열, 불이 켜졌는지 확인하는 배열, 총 3개의 배열을 사용했는데 이게 메모리에 엄청난 영향을 준 것 같다.

BFS를 돌며 큐에서 하나 빼낼때마다, 그 방에서 켤 수 있는 모든 방들의 불을 켜준뒤 light 변수를 1씩 증가시켜주었다.


느낀점

메모리와 시간이 어마어마하다.

다른 사람들은 DFS로 풀고 3차원 배열도 안 썼던데 한 번 고민해보면 좋을 것 같다.


코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;

public class BOJ11967 {
  static int N, M;
  static ArrayList<Pos>[][] map; // 어느 방의 불을 켤 수 있는지 저장
  static boolean[][] room; // 불이 켜져있는지
  static boolean[][][] visited; // 방문확인
  static int light; // 불 켜진 방의 개수
  static int[][] dir = {{-1, 0}, {1, 0}, {0, -1}, {0, 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 ArrayList[N+1][N+1];
    room = new boolean[N+1][N+1];
    visited = new boolean[N+1][N+1][10000];
	
    for (int i = 0; i < M; i++) {
      st = new StringTokenizer(br.readLine(), " ");
      int x = Integer.parseInt(st.nextToken());
      int y = Integer.parseInt(st.nextToken());
      int a = Integer.parseInt(st.nextToken());
      int b = Integer.parseInt(st.nextToken());
		
      if(map[x][y] == null) {
    	map[x][y] = new ArrayList<Pos>();
      }
      map[x][y].add(new Pos(a, b));
    } // end for
		
    light = 1;
    visited[1][1][light] = true;
    room[1][1] = true;
    Queue<Pos> q = new LinkedList<Pos>();
    q.offer(new Pos(1, 1));
      while(!q.isEmpty()) {
    	// 현재 위치에서 불을 킬 수 있는 장소들 불을 킨다
    	Pos cur = q.poll();
    	if(map[cur.x][cur.y] != null) { // 불 켤 수 있는 스위치가 존재한다면
    	  for (int i = 0; i < map[cur.x][cur.y].size(); i++) {
            Pos next = map[cur.x][cur.y].get(i);
            if(room[next.x][next.y] == false) {
              room[next.x][next.y] = true; // 불을 켜주고
              light++; // 불켜진 방의 개수를 증가시킨다
            }
          }
        } // end if
			
        // 불이 켜져있는 곳으로 상하좌우 이동한다
        for (int i = 0; i < 4; i++) {
          int nx = cur.x + dir[i][0];
          int ny = cur.y + dir[i][1];
          if(isIn(nx, ny) && !visited[nx][ny][light] && room[nx][ny]) { // 범위 내에 있고, 방문한 적 없고, 불이 켜져있다면 이동
            visited[nx][ny][light] = true;
            q.offer(new Pos(nx, ny));
          }
        } // end for
      } // end while 
		
      System.out.println(light);
  }
	
  public static boolean isIn(int x, int y) {
    return x>=1 && x<=N && y>=1 && y<=N;
  }
	
  static class Pos {
    int x, y;

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

    @Override
    public String toString() {
      return "Pos [x=" + x + ", y=" + y + "]";
    }
  }
}