본문 바로가기
알고리즘 문제풀이/SW Expert

[SW Expert 1953] 탈주범 검거

by 선서니 2023. 4. 4.

[문제 바로가기]👇

 

SW Expert Academy

SW 프로그래밍 역량 강화에 도움이 되는 다양한 학습 컨텐츠를 확인하세요!

swexpertacademy.com

 

 

 

 

풀이

  • 탈주범이 맨홀 뚜껑부터 시작해 시간당 1의 거리만큼 계속 이동
  • 탈주범이 있을 수 있는 장소를 찾아야 하기 때문에 bfs로 같은 거리에 있는 위치들을 모두 탐색
  • 탈주범이 탈출 후 소요된 시간(L) == bfs 깊이가 되면 탐색 종료

 

1. 입력 받기

	static int[] dr = {-1,0,1,0}; //상우하좌
	static int[] dc = {0,1,0,-1}; //상우하좌
	static int N, M, L, answer;
	static int[][] map;
	static boolean[][] v;
	
	public static void main(String[] args) throws NumberFormatException, IOException {
		System.setIn(new FileInputStream("res/input_sw1953.txt"));
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringBuilder sb = new StringBuilder();
		int T = Integer.parseInt(br.readLine());
		
		for(int t=1; t<=T; t++) {
			StringTokenizer st = new StringTokenizer(br.readLine(), " ");
			N = Integer.parseInt(st.nextToken());
			M = Integer.parseInt(st.nextToken());
			int r = Integer.parseInt(st.nextToken());
			int c = 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());
				}
			}
			
			v = new boolean[N][M];
			answer = 0;
			bfs(r,c, map[r][c]);
			sb.append("#").append(t).append(" ").append(answer).append("\\n");
		}
		System.out.println(sb);
		br.close();
	}

 

2. bfs

큐에 넣을 수 있는 것들을 체크할 때 현재 파이프와 이동할 곳에 있는 파이프가 서로 연결되어 있어야만 이동할 수 있기 때문에 연결 여부를 체크해줘야 한다

static void bfs(int r, int c, int pipe) {
		ArrayDeque<int[]> q = new ArrayDeque<>();
		answer++;
		v[r][c] = true;
		q.offer(new int[] {r,c, pipe, 1}); // r,c, 파이프 번호, depth
		
		while(!q.isEmpty()) {
			int[] cur = q.poll();
			if(cur[3]==L) break;
			
			for(int d=0; d<4; d++) {
				int nr = cur[0] + dr[d];
				int nc = cur[1] + dc[d];
				
				if(0<=nr&&nr<N && 0<=nc&&nc<M && !v[nr][nc] && map[nr][nc]!=0) {
					// 현재 파이프와 이동 가능한 것만 큐에 추가
					if(isConnected(nr, nc, cur[2], d)) { 
						answer++;
						v[nr][nc] = true;
						q.offer(new int[] {nr,nc, map[nr][nc], cur[3]+1});
					}
				}
			}
		}
}

 

2-1. 파이프 연결 여부 확인

현재 이동하려는 방향의 반대 방향을 이동할 파이프가 이동할 수 있으면 연결 되어 있다고 판단

static boolean isConnected(int r, int c, int pipe, int d) {
		int cPipe = map[r][c];
		
		if(d==0) { // 현재 파이프 -이동할 파이프(상 - 하)
			if((pipe==1||pipe==2||pipe==4||pipe==7) &&
				(cPipe==1||cPipe==2||cPipe==5||cPipe==6)) return true;
		}
		else if(d==1) { // 현재 파이프 -이동할 파이프(우 - 좌)
			if((pipe==1||pipe==3||pipe==4||pipe==5) &&
					(cPipe==1||cPipe==3||cPipe==6||cPipe==7)) return true;
		}
		else if(d==2) { // 현재 파이프 -이동할 파이프(하 - 상)
			if((pipe==1||pipe==2||pipe==5||pipe==6) &&
					(cPipe==1||cPipe==2||cPipe==4||cPipe==7)) return true;
		}
		else { // 현재 파이프 -이동할 파이프(좌 - 우)
			if((pipe==1||pipe==3||pipe==6||pipe==7) &&
					(cPipe==1||cPipe==3||cPipe==4||cPipe==5)) return true;
		}
		return false;
}

 

전체 코드

package Day_0404;

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

public class Solution {
	static int[] dr = {-1,0,1,0}; //상우하좌
	static int[] dc = {0,1,0,-1}; //상우하좌
	static int N, M, L, answer;
	static int[][] map;
	static boolean[][] v;
	
	public static void main(String[] args) throws NumberFormatException, IOException {
		System.setIn(new FileInputStream("res/input_sw1953.txt"));
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringBuilder sb = new StringBuilder();
		int T = Integer.parseInt(br.readLine());
		
		for(int t=1; t<=T; t++) {
			StringTokenizer st = new StringTokenizer(br.readLine(), " ");
			N = Integer.parseInt(st.nextToken());
			M = Integer.parseInt(st.nextToken());
			int r = Integer.parseInt(st.nextToken());
			int c = 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());
				}
			}
			
			v = new boolean[N][M];
			answer = 0;
			bfs(r,c, map[r][c]);
			sb.append("#").append(t).append(" ").append(answer).append("\\n");
		}
		System.out.println(sb);
		br.close();
	}
	
	static void bfs(int r, int c, int pipe) {
		ArrayDeque<int[]> q = new ArrayDeque<>();
		answer++;
		v[r][c] = true;
		q.offer(new int[] {r,c, pipe, 1}); // r,c, 파이프 번호, depth
		
		while(!q.isEmpty()) {
			int[] cur = q.poll();
			if(cur[3]==L) break;
			
			for(int d=0; d<4; d++) {
				int nr = cur[0] + dr[d];
				int nc = cur[1] + dc[d];
				
				if(0<=nr&&nr<N && 0<=nc&&nc<M && !v[nr][nc] && map[nr][nc]!=0) {
					// 현재 파이프와 이동 가능한 것만 큐에 추가
					if(isConnected(nr, nc, cur[2], d)) { 
						answer++;
						v[nr][nc] = true;
						q.offer(new int[] {nr,nc, map[nr][nc], cur[3]+1});
					}
				}
			}
		}
	}
	
	static boolean isConnected(int r, int c, int pipe, int d) {
		int cPipe = map[r][c];
		
		if(d==0) { // 현재 파이프 -이동할 파이프(상 - 하)
			if((pipe==1||pipe==2||pipe==4||pipe==7) &&
				(cPipe==1||cPipe==2||cPipe==5||cPipe==6)) return true;
		}
		else if(d==1) { // 현재 파이프 -이동할 파이프(우 - 좌)
			if((pipe==1||pipe==3||pipe==4||pipe==5) &&
					(cPipe==1||cPipe==3||cPipe==6||cPipe==7)) return true;
		}
		else if(d==2) { // 현재 파이프 -이동할 파이프(하 - 상)
			if((pipe==1||pipe==2||pipe==5||pipe==6) &&
					(cPipe==1||cPipe==2||cPipe==4||cPipe==7)) return true;
		}
		else { // 현재 파이프 -이동할 파이프(좌 - 우)
			if((pipe==1||pipe==3||pipe==6||pipe==7) &&
					(cPipe==1||cPipe==3||cPipe==4||cPipe==5)) return true;
		}
		return false;
	}

}

'알고리즘 문제풀이 > SW Expert' 카테고리의 다른 글

[SW Expert 5656] 벽돌 깨기  (0) 2023.02.25
[SW 1247] 최적 경로  (0) 2023.02.23
[SW 1873] 상호의 배틀필드  (0) 2023.02.23
[SW Expert 5215] 햄버거 다이어트  (0) 2023.02.16
[SW Expert 4012] 요리사  (2) 2023.02.16

댓글