Development Palette
b2206_벽부수고이동하기; 본문
https://www.acmicpc.net/problem/2206
2206번: 벽 부수고 이동하기
N×M의 행렬로 표현되는 맵이 있다. 맵에서 0은 이동할 수 있는 곳을 나타내고, 1은 이동할 수 없는 벽이 있는 곳을 나타낸다. 당신은 (1, 1)에서 (N, M)의 위치까지 이동하려 하는데, 이때 최단 경로
www.acmicpc.net
package com.BFS.b2206_벽부수고이동하기;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;
// 1,1 ~ N,M 까지 가는길의 총합이 1이거나 0일때 "최단거리"
public class Main {
static int N;
static int M;
// 우 하 좌 상
static int [] dr = {0,1,0,-1};
static int [] dc = {1,0,-1,0};
static int [][] map;
static int [][] min;
static boolean [][][] visited;
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 int[N+1][M+1];
min = new int[N+1][M+1]; // 해당 좌표까지 가기 위해 이동한 거리를 저장
visited = new boolean[N+1][M+1][2]; // r,c,0 : 벽없을때 / r,c,1 : 벽있을때
// 입력
String str;
for (int r = 1; r <= N; r++) {
str = br.readLine();
for (int c = 1; c <= M; c++) {
map[r][c] = str.charAt(c-1)-'0'; // 0 빈방, 1 벽
}
}
System.out.println(bfs(new int[]{1,1}));
//print();
br.close();
}
private static int bfs(int [] v) {
Queue<int []> queue = new LinkedList<>();
queue.add(new int[]{v[0],v[1],0,1}); // {r,c,지금까지 벽을 부셨던적이 있는지 없는지 정보를 담기 위함(부셨으면 1 안부셨으면 0)}
// 벽부신적있는지의유무를 매번 갖고 다녀야함!!! 그래야 다음 경로를 갈수있는지 없는지 판단할수있기때문
min[v[0]][v[1]]=1;
visited[v[0]][v[1]][0] = true;
int nr;
int nc;
while (!queue.isEmpty()){
v = queue.poll();
int crash = v[2];
// 제일 처음에 N,M에 도착한경우가 최단거리이므로 N,M에 도착했을때 리턴해주기
if(v[0]==N && v[1]==M) return min[N][M];
for (int d = 0; d < 4; d++) {
nr = v[0] + dr[d];
nc = v[1] + dc[d];
if(nr<1||nc<1||nr>N||nc>M) continue;
// 벽인데 방문안한곳 (부신적 없는 벽)...... 을 방문하기 위해서는 이전에 벽을 부신적 있으면 안됨
// visited -> r,c,0 : 벽없을때 방문 확인 / r,c,1 : 벽있을때 방문 확인
// crash : 벽을 부신 전적유무(이전에 벽을 부신적이 있다면 실행 x)
if(map[nr][nc]==1 && !visited[nr][nc][1] && crash==0) {
visited[nr][nc][1] = true; // 무조건 벽을 부신경우의 방문이니까 1
min[nr][nc] = min[v[0]][v[1]] + 1; // 이동수 증가
queue.add(new int[]{nr, nc, 1}); // 부신걸 체크(1표시)하고 다음 경로 탐색하기위해 큐에 넣어줌. 이때 crash 자체를 1로바꾸면 안된다.
// 왜냐면 추후에 여기서 넣은 큐의 탐색이 종료되고 다음 큐를 탐색할때!! 부신걸 다시원래대로(안부셨다고)해야하기 때문에 crash를 1로 바꾸지 않는다
}
// 벽을 부셨는지 안부셨는지 상관없이 방문여부만 확인하고 실행
if(map[nr][nc]==0 && !visited[nr][nc][crash] ){
visited[nr][nc][crash]= true; // crash : 벽을 부셨는지 안부셨는지 상관없이 실행되기때문에, 이전에 부셨는지 안부셨는지에 따라 방문표시
min[nr][nc] = min[v[0]][v[1]] + 1;
queue.add(new int[]{nr,nc,crash}); // 큐에 넣는것도 방문표시와 마찬가지로, 부숨유무를 넣어준다
}
//print();
}
}
return -1; // 위에서 리턴하지 못하는 경우는 N,M에 도착하지 못하는 경우
}
private static void print() {
for (int r = 1; r <= N; r++) {
for (int c = 1; c <= M; c++) {
System.out.print(min[r][c]+" ");
}
System.out.println();
}
System.out.println("----------");
}
}
/*
5 5
00000
11101
00001
01111
00010
*/
package com.BFS.b2206_벽부수고이동하기;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;
// min 배열을 만들지 않고 큐에 같이 담아서 증가시키는 코드
public class Main2 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
int N = Integer.parseInt(st.nextToken());
int M = Integer.parseInt(st.nextToken());
int [][]map = new int[N][M];
String str;
for (int r = 0; r < N; r++) {
str = br.readLine();
for (int c = 0; c < M; c++) {
map[r][c] = str.charAt(c)-'0';
}
}
System.out.println(bfs(map,N,M));
br.close();
}
private static int bfs(int [][] map,int N, int M) {
int [] dr = {0,1,0,-1};
int [] dc = {1,0,-1,0};
Queue<int []> queue = new LinkedList<>();
boolean [][][] visited = new boolean[N][M][2];
queue.add(new int[]{0,0,0,1});
visited[0][0][0] = true;
int [] v;
int nr;
int nc;
int crash;
int min;
while (!queue.isEmpty()){
v = queue.poll();
crash = v[2];
min = v[3];
if(v[0]==N-1 && v[1]==M-1) return min;
for (int d = 0; d < 4; d++) {
nr = v[0] + dr[d];
nc = v[1] + dc[d];
if(nr<0||nc<0||nr>=N||nc>=M) continue;
if(map[nr][nc]==1 && !visited[nr][nc][1] && crash==0) {
visited[nr][nc][1] = true;
queue.add(new int[]{nr, nc, 1,min+1});
}
if(map[nr][nc]==0 && !visited[nr][nc][crash]){
visited[nr][nc][crash]= true;
queue.add(new int[]{nr,nc,crash,min+1});
}
}
}
return -1;
}
}
/*
8 8
01000100
01010100
01010100
01010100
01010100
01010100
01010100
00010100
*/
'Algorithm > Baekjoon' 카테고리의 다른 글
b1331_나이트투어 (0) | 2021.10.10 |
---|---|
b11401_이항계수3 (0) | 2021.10.04 |
[파스칼의 삼각형] b11050_이항계수1 (0) | 2021.10.04 |
b17144_미세먼지안녕 (0) | 2021.09.24 |
[KMP알고리즘]b1786_찾기 (0) | 2021.09.24 |
Comments