초보개발자 긍.응.성
[Java] 1953. 탈주범 검거 본문
모의 SW 역량테스트 1953. 탈주범 검거
문제 출처: https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV5PpLlKAQ4DFAUq
파이프와 방향을 표현하기 위해 상하좌우를 비트로 표현. BFS를 이용하여 문제를 해결.
전체 소스코드 아래 추가적인 설명이 있습니다.
- 전체 소스코드
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;
public class Solution {
static class Point {
int x, y;
int time;
public Point(int x, int y, int time) {
this.x = x;
this.y = y;
this.time = time;
}
public String toString() {
return "(" + x + ", " + y + ") = time " + time;
}
}
static int N, M, L;
static int startX, startY;
static int[][] map;
static int[][] dir = { { 0, 1 }, { 0, -1 }, { 1, 0 }, { -1, 0 } };
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
int T = Integer.parseInt(br.readLine());
for (int test_case = 1; test_case <= T; test_case++) {
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());
startX = Integer.parseInt(st.nextToken());
startY = Integer.parseInt(st.nextToken());
L = Integer.parseInt(st.nextToken());
map = new int[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());
}
}
int count = 0;
boolean[][] visit = new boolean[N][M];
Queue<Point> q = new LinkedList<>();
q.add(new Point(startX, startY, 1));
visit[startX][startY] = true;
while (!q.isEmpty()) {
Point p = q.poll();
if (p.time <= L)
count++;
else
break;
int dirInfo = getDirInfo(map[p.x][p.y]);
for (int i = 0; i < 4; i++) {
if ((dirInfo >> i & 1) == 1) {
int nextX = p.x + dir[i][0];
int nextY = p.y + dir[i][1];
if (nextX >= 0 && nextX < N && nextY >= 0 && nextY < M) { // in boundary
if (visit[nextX][nextY] == false && map[nextX][nextY] != 0) {
int nextDir = getDirInfo(map[nextX][nextY]);
int j;
if (i % 2 == 0)
j = i + 1;
else
j = i - 1;
if ((nextDir >> j & 1) == 1) {
q.add(new Point(nextX, nextY, p.time+1));
visit[nextX][nextY] = true;
}
}
}
}
}
}
bw.append("#"+test_case+" "+count+"\n");
}
bw.flush();
bw.close();
br.close();
}
// 상하좌우 4개의 비트로 표현
private static int getDirInfo(int val) {
int dir = 0;
switch (val) {
case 1:
dir = 15;
break;
case 2:
dir = 12;
break;
case 3:
dir = 3;
break;
case 4:
dir = 9;
break;
case 5:
dir = 5;
break;
case 6:
dir = 6;
break;
case 7:
dir = 10;
break;
}
return dir;
}
}
- 풀이
시간 L동안 시작점에서 출발하여 시간이 지날 수 록 존재할 수 있는 위치는 이어져있는 동굴로 퍼져나갈 수 있다. 해결 방식은 BFS로 잡고 위치와 그 위치에 도달할 수 있는 시간을 변수로 가진 클래스 Point를 선언하였다.
- Point Class
static class Point {
int x, y;
int time;
public Point(int x, int y, int time) {
this.x = x;
this.y = y;
this.time = time;
}
public String toString() {
return "(" + x + ", " + y + ") = time " + time;
}
}
큐에 시작점을 담고 큐가 빌 때까지 탐색을 진행한다. 탐색은 큐에서 하나의 Point를 꺼내어 해당 위치에 도달할 시간을 체크한다. L보다 더 오래걸려 해당 위치로 왔다면 탐색을 종료하고 아니라면 시간 내 존재할 수 있으므로 카운트를 한다. 이어서 이동할 수 있는 길에 대해 찾아 큐에 담아준다.
이동할 수 있는 길을 찾는 방법은 다음과 같다.
지도에서 값을 들고와 동굴의 모양에 따라 이동할 수 있는 곳에 대한 정보 값을 받아온다. 상하좌우를 각각 1비트를 할당하여 네 자릿수의 비트로 표현하기로한다. 이를 비트 연산자로 분석하여 해당 위치의 비트가 켜져 있으면 이동할 수 있는 방향이므로 해당 위치에 대해 유망하다고 판단한다. 하지만 이동할 수 있는 방향이 동굴이 존재하지 않거나 존재해도 통로가 맞지 않을 수도 있다. 그렇기 때문에 이동할 방향에 대해서도 통로가 일치함을 비트 연산자를 이용하여 확인한 후 유망하다면 다음 위치를 큐에 넣는다.
// 상하좌우 4개의 비트로 표현
private static int getDirInfo(int val) {
int dir = 0;
switch (val) {
case 1:
dir = 15;
break;
case 2:
dir = 12;
break;
case 3:
dir = 3;
break;
case 4:
dir = 9;
break;
case 5:
dir = 5;
break;
case 6:
dir = 6;
break;
case 7:
dir = 10;
break;
}
return dir;
}
위 작업을 반복하여 시간이 L보다 크다면 탐색을 멈추고 현재까지의 count를 출력하여 해결하였다.
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
int T = Integer.parseInt(br.readLine());
for (int test_case = 1; test_case <= T; test_case++) {
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());
startX = Integer.parseInt(st.nextToken());
startY = Integer.parseInt(st.nextToken());
L = Integer.parseInt(st.nextToken());
map = new int[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());
}
}
int count = 0;
boolean[][] visit = new boolean[N][M];
Queue<Point> q = new LinkedList<>();
q.add(new Point(startX, startY, 1));
visit[startX][startY] = true;
while (!q.isEmpty()) {
Point p = q.poll();
if (p.time <= L)
count++;
else
break;
int dirInfo = getDirInfo(map[p.x][p.y]);
for (int i = 0; i < 4; i++) {
if ((dirInfo >> i & 1) == 1) {
int nextX = p.x + dir[i][0];
int nextY = p.y + dir[i][1];
if (nextX >= 0 && nextX < N && nextY >= 0 && nextY < M) { // in boundary
if (visit[nextX][nextY] == false && map[nextX][nextY] != 0) {
int nextDir = getDirInfo(map[nextX][nextY]);
int j;
if (i % 2 == 0)
j = i + 1;
else
j = i - 1;
if ((nextDir >> j & 1) == 1) {
q.add(new Point(nextX, nextY, p.time+1));
visit[nextX][nextY] = true;
}
}
}
}
}
}
bw.append("#"+test_case+" "+count+"\n");
}
bw.flush();
bw.close();
br.close();
}
'코딩테스트 > SW Expert Academy' 카테고리의 다른 글
[Java] 2382. 미생물 격리 (0) | 2020.04.13 |
---|---|
[Java] 2117. 홈 방범 서비스 (0) | 2020.04.13 |
[Java] 2105. 디저트 카페 (0) | 2020.04.13 |
[Java] 9088. 다이아몬드 (0) | 2020.03.26 |
[Java] 8998. 세운이는 내일 할거야 (0) | 2020.03.23 |
[Java] 8993. 하지 추측 (0) | 2020.03.23 |
[Java] 8934. 팰린드롬 공포증 (0) | 2020.03.20 |
[Java] 8898. 3차원 농부 (0) | 2020.03.20 |