SWEA 1953 - 탈주범 검거
Updated:
Java
1953 번 - 탈주범 검거
문제
지하 터널 지도와 맨홀 뚜껑의 위치, 경과된 시간이 주어질 때 탈주범이 위치할 수 있는 장소의 개수를 계산하는 프로그램을 작성하라.
접근 방법
우선 파이프의 모양에 따른 방향들을 설정하였다.
상, 하, 좌, 우를 나타내는 1차원 배열 2개를 설정하고(Y,X)
각 파이프 타입에 따른 방향을 인덱스로 주어 방향들을 설정하였다.
BFS 사용하여 파이프를 탐색한다.
최대 L시간 만큼 반복하여 파이프가 갈 수 있는 길을 탐색한다.
현재 위치의 파이프 모양에 따라 4 방향 중 골라 이동하는데,
다음 파이프의 모양이 현재 가려는 방향의 반대 방향이어서, 이어지는지 확인하였다.
이는, 현재 이동하려는 위치의 파이프 타입에 있는 방향 인덱스 중, 현재 꽂으려는 방향과 반대로인 방향이 있으면 꽂을 수 있다.
BFS가 종료한 후, 맵에 방문한 파이프의 개수를 센다.
코드
import java.io.*;
import java.util.*;
// 탈주범 검거
class Solution {
static int result = 0, n,m, r,c ,L;
// 상 하 좌 우
static int[] dy = {-1,1,0,0};
static int[] dx = {0,0,-1,1};
// 파이프의 모양에 따른 방향들
static int[][] dir = { {}, {0,1,2,3}, {0,1}, {2,3}, {0,3}, {1,3}, {1,2}, {0,2}};
// 맵
static int[][] map;
static boolean[][] vis;
public static void main(String []args) throws Exception {
System.setIn(new FileInputStream("res/input.txt")); //제출 할 때 주석해야함
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer stk;
int tc = stoi(br.readLine());
for(int tidx = 1; tidx <= tc; tidx++) {
result = 0;
stk = new StringTokenizer(br.readLine());
n = stoi(stk.nextToken());
m = stoi(stk.nextToken());
r = stoi(stk.nextToken());
c = stoi(stk.nextToken());
L = stoi(stk.nextToken());
map = new int[n][m];
vis = new boolean[n][m];
for(int i = 0; i < n; i++) {
stk = new StringTokenizer(br.readLine());
for(int j = 0; j < m; j++) {
map[i][j] = stoi(stk.nextToken());
}
}
BFS(r,c,map[r][c]);
// 방문했던 모든 파이프의 개수를 센다
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
if(vis[i][j])
result++;
}
}
System.out.println("#" + tidx + " " + result);
}
}
static void BFS(int y, int x, int idx) {
Queue<int[]> queue = new LinkedList<int[]>();
queue.add(new int[] {y,x, idx});
int loopCnt = 0;
int[] temp;
int ny,nx, nextGo, curDir;
if(L > 0) // 1초 일때는 현재 위치만 이동가능 하다
vis[y][x] = true;
// 주어진 시간 만큼 이동한다.
while(L-- > 1) {
loopCnt = queue.size();
for(int k = 0; k < loopCnt; k++) {
temp = queue.poll();
y = temp[0];
x = temp[1];
nextGo = temp[2];
for(int i = 0; i < dir[nextGo].length; i++) {
curDir = dir[nextGo][i];
ny = y + dy[curDir];
nx = x + dx[curDir];
// 지도 안에 있고, 방문하지 않았으며, 파이프가 있고, 파이프끼리 연결 될 수 있으면
if(isIn(ny,nx) && !vis[ny][nx] && map[ny][nx] != 0 && isConn(curDir, ny, nx)) {
vis[ny][nx] = true;
queue.add(new int[] {ny, nx, map[ny][nx] });
}
}
}
}
}
// 연결 될 수 있는가
static boolean isConn(int fromD, int y, int x) {
int scape = map[y][x]; // 꽂으려는 파이프의 현재 모양
int wantD = 0;
if(fromD == 0) // 올라오는 방향
wantD = 1; // 꽂히는 방향
else if(fromD == 1)
wantD = 0;
else if(fromD == 2)
wantD = 3;
else if(fromD == 3)
wantD = 2;
// 꽂히는 방향이 현재 지도에 있는 파이프에 있는지 확인한다.
for(int i = 0; i < dir[scape].length; i++) {
if(wantD == dir[scape][i])
return true;
}
return false;
}
// 주어진 범위 안에 있는가
public static boolean isIn(int y, int x){
if(y < 0 || y >= n || x < 0 || x >= m)
return false;
return true;
}
static int stoi(String str) {
return Integer.parseInt(str);
}
}
총평
후기
L이 1일때 처음 위치도 기록되지 않아, 이를 고려해야겠다는 생각만 하고 실제로 적용하지 않아 처음에는 틀렸다.
이런 사소한 것이 합격 불합격을 나타내니, 매번 생각 날 때마다 주석으로 달자.
나중에 분명히 잊는다.
개선할 점
없