티스토리 뷰
https://www.acmicpc.net/problem/1175
1175번: 배달
어제 선물을 모두 포장한 민식이는 이제 선물을 배달하려고 한다. 민식이가 선물을 배달할 곳은 이 문제를 읽는 사람들이 앉아 있는 교실이다. 교실은 직사각형모양이고, 모두 같은 크기의 정사
www.acmicpc.net

문제
어제 선물을 모두 포장한 민식이는 이제 선물을 배달하려고 한다. 민식이가 선물을 배달할 곳은 이 문제를 읽는 사람들이 앉아 있는 교실이다. 교실은 직사각형모양이고, 모두 같은 크기의 정사각형 블록으로 나누어져 있다.
입력으로 교실의 지도가 주어진다. 각각의 정사각형 블록은 다음과 같이 4가지 종류가 있다.
- S: 지금 민식이가 있는 곳이다. 이곳이 민식이가 배달을 시작하는 곳이고 1개만 있다.
- C: 민식이가 반드시 선물을 배달해야 하는 곳이다. 이러한 블록은 정확하게 2개 있다.
- #: 민식이가 갈 수 없는 곳이다.
- .: 민식이가 자유롭게 지나갈 수 있는 곳이다.
민식이가 한 블록 동서남북으로 이동하는데는 1분이 걸린다. 민식이는 네가지 방향 중 하나로 이동할 수 있으며, 교실을 벗어날 수 없다. 민식이가 선물을 배달해야 하는 곳에 들어갈 때, 민식이는 그 곳에 있는 사람 모두에게 선물을 전달해야 한다. 이 상황은 동시에 일어나며, 추가적인 시간이 소요되지 않는다.
민식이는 어느 누구도 자신을 보지 않았으면 하기 때문에, 멈추지 않고 매 시간마다 방향을 바꿔야 한다. 이 말은 같은 방향으로 두 번 연속으로 이동할 수 없다는 말이다. 민식이가 선물을 모두 배달하는데 걸리는 시간의 최솟값을 구하는 프로그램을 작성하시오.
유형 : BFS
접근 방식
- 개인적으로 어려운 BFS의 조건 중 하나는 갔던 곳을 다시 가는 것이다.
- 갔던 곳을 다시 간다고? : 애초에 방문 체크를 하는 이유가 다시 가는 걸(중복)을 방지하기 위해 하는 것이 아닌가?
- 다시 생각해보자 : 단순히 좌표는 동일할지라도 해당 탐색 위치는 중복이지 않은 경우이다.
- 구분할 수 있는 기준은 2개이다.
- 해당 (x,y) 위치로 들어오는 방향 (방향 중복 방지를 위해서도 있다)
- 찾은 개수 : 2와 4중 찾은 값 -> 2개 찾았으면 6
- already : 이미 찾았는지 확인하는 방법
static boolean already(int cur,int t){
// 현재 찾은 값을 cur이라 했을 때 t라는 값을 이미 찾았는지 확인하는 메소드
int[] arr = {2,4};
for(int i=1;i>=0;i--){
if(cur >= arr[i]){
if(t == cur)
return true; // 해당 값을 가지고 있다.
cur -= arr[i];
}
}
return false;
}
전체 코드
import java.util.*;
import java.io.*;
public class Main {
static int n = 0;
static int m = 0;
static int sx = 0;
static int sy = 0;
static int[][] board;
static int result = -1;
static int[] dx = {0,0,-1,1};
static int[] dy = {1,-1,0,0};
public static void main(String[] args) throws Exception {
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(bf.readLine(), " ");
n = Integer.parseInt(st.nextToken());
m = Integer.parseInt(st.nextToken());
board = new int[n+1][m+1];
int land = 2;
for(int i=1;i<=n;i++){
String line = bf.readLine();
for(int j=1;j<=m;j++){
char cur = line.charAt(j-1);
if(cur == '#'){
board[i][j] = -1; // 벽
}else if(cur == 'S'){
sx = i;
sy = j; // 시작 좌표
}else if(cur == 'C'){
board[i][j] = land; // 도착지 (2개이고 구분하기 위해 각각 2,4 설정)
land *= 2;
}
}
}
bfs();
System.out.println(result);
bf.close();
}
static void bfs(){
Queue<Node> q = new LinkedList<>();
int[][][][] v = new int[n+1][m+1][4][7]; // 행 , 열 , 방향 , 찾은 개수
for(int i=0;i<4;i++){
int nx = sx + dx[i];
int ny = sy + dy[i];
if(isOut(nx,ny))
continue;
if(board[nx][ny] == 0){
v[nx][ny][i][0] = 1;
q.add(new Node(nx,ny,i,0));
}else if(board[nx][ny] >= 1){
v[nx][ny][i][board[nx][ny]] = 1;
q.add(new Node(nx,ny,i,board[nx][ny]));
}
}
while(!q.isEmpty()){
Node cur = q.poll();
if(cur.f == 6){
if(result == -1 || result > v[cur.x][cur.y][cur.d][cur.f]){
result = v[cur.x][cur.y][cur.d][cur.f];
}
return;
}
for(int i=0;i<4;i++){
if(cur.d == i)
continue;
int nx = cur.x + dx[i];
int ny = cur.y + dy[i];
if(isOut(nx,ny))
continue;
if(board[nx][ny] == 0){
if(v[nx][ny][i][cur.f] == 0 || v[nx][ny][i][cur.f] > v[cur.x][cur.y][cur.d][cur.f] + 1){
v[nx][ny][i][cur.f] = v[cur.x][cur.y][cur.d][cur.f] + 1; // 빈 좌표 (그냥 이동)
q.add(new Node(nx,ny,i,cur.f));
}
}else if(board[nx][ny] >= 1){
if(already(cur.f,board[nx][ny])){
if(v[nx][ny][i][cur.f] == 0 || v[nx][ny][i][cur.f] > v[cur.x][cur.y][cur.d][cur.f] + 1){
v[nx][ny][i][cur.f] = v[cur.x][cur.y][cur.d][cur.f] + 1; // (이미 찾았을 경우)
q.add(new Node(nx,ny,i,cur.f));
}
}else{
if(v[nx][ny][i][cur.f + board[nx][ny]] == 0 || v[nx][ny][i][cur.f + board[nx][ny]] > v[cur.x][cur.y][cur.d][cur.f] + 1 ){
v[nx][ny][i][cur.f + board[nx][ny]] = v[cur.x][cur.y][cur.d][cur.f] + 1;
q.add(new Node(nx,ny,i,cur.f + board[nx][ny])); // (새로 찾은 경우)
}
}
}
}
}
}
static boolean already(int cur,int t){
// 현재 찾은 값을 cur이라 했을 때 t라는 값을 이미 찾았는지 확인하는 메소드
int[] arr = {2,4};
for(int i=1;i>=0;i--){
if(cur >= arr[i]){
if(t == cur)
return true;
cur -= arr[i];
}
}
return false;
}
static boolean isOut(int nx,int ny){
if(nx < 1 || nx > n || ny < 1 || ny > m)
return true; // 밖을 나갈 경우
if(board[nx][ny] == -1)
return true; // 벽
return false;
}
}
class Node{
int x;
int y;
int d;
int f;
Node(int x,int y,int d,int f){
this.x = x; // x 좌표
this.y = y; // y 좌표
this.d = d; // d 방향
this.f = f; // f 몇개 찾았는지
}
}'알고리즘 > 백준' 카테고리의 다른 글
| 백준 9470 (Strahler 순서) - java (1) | 2024.01.05 |
|---|---|
| 백준 2325 (개코전쟁) - java (1) | 2024.01.05 |
| 백준 2616 (소형기관차) - java (1) | 2024.01.05 |
| 백준 14950 (정복자) - java (1) | 2023.12.28 |
| 백준 16985 (Maaaaaaaaaze) - java (1) | 2023.12.21 |
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- 백준 #14863 #서울에서 경산까지 #java #자바
- Java
- 백준 #17940 #주식 #자바 #java
- 백준 #1759 #암호 만들기
- 백준 #인구 이동 #16234
- 백준 #18405 #경쟁적 전염
- 백준 #1584 #게임 #java #자바
- 백준 #13549 #숨바꼭질3
- 백준 #28140 #빨강~ 빨강~ 파랑! 파랑! 달콤한 솜사탕! #java #자바
- 자바
- 백준 #
- 백준 #1987 #알파벳 #자바 #java
- 백준 #12014 #주식 #자바 #java
- 백준 #2580 #스도쿠
- 행복합시다.
- 백준 #16973 #직사각형 탈출
- 백준 #2636 #치즈
- 백준 #15686 #치킨 배달
- 백준 #4963 #섬의 개수
- 백준 #1325 #효율적인 해킹
- 백준 #25603 #짱해커 이동식 #java #자바
- 17394
- 17218
- 올해보다
- 백준 #5721 #사탕 줍기 대회 #java #자바
- 백준 #3980 #선발 명단
- 백준 #치즈 #2638
- 백준
- 자바 #JAVA
- 백준 #다리 만들기 #2146
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 8 | 9 | 10 | 11 | 12 | 13 | 14 |
| 15 | 16 | 17 | 18 | 19 | 20 | 21 |
| 22 | 23 | 24 | 25 | 26 | 27 | 28 |
글 보관함