morenow
morenow
morenow
전체 방문자
오늘
어제
  • 분류 전체보기 (83)
    • 스프링부트와 AWS로 혼자 구현하는 웹 서비스 (5)
    • [MSA] Spring Cloud로 개발하는 마이.. (14)
    • Baekjoon Online Judge (40)
    • Programmers (11)
    • Spring Boot (7)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • Id Token
  • lost update
  • 백준 파이어스톰
  • 백준20058C++
  • HTTP Interface
  • Feign Client
  • Spring Boot
  • Open Feign
  • JWT단점
  • 마법사 상어와 파이어스톰
  • B+ Tree
  • write skew
  • Refresh Token Refresh
  • B Tree
  • successHandler
  • copy up
  • jwt
  • dirty write
  • re-distribution
  • HttpExchange

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
morenow
Baekjoon Online Judge

[BOJ] 1600 : 말이 되고픈 원숭이 (C++) with BFS

Baekjoon Online Judge

[BOJ] 1600 : 말이 되고픈 원숭이 (C++) with BFS

2023. 8. 29. 18:37

https://www.acmicpc.net/problem/1600

 

1600번: 말이 되고픈 원숭이

첫째 줄에 정수 K가 주어진다. 둘째 줄에 격자판의 가로길이 W, 세로길이 H가 주어진다. 그 다음 H줄에 걸쳐 W개의 숫자가 주어지는데, 0은 아무것도 없는 평지, 1은 장애물을 뜻한다. 장애물이 있

www.acmicpc.net

걸린 시간 : 47분 25초


알고리즘 아이디어

BFS의 응용판, 3차원으로 푸는 문제이다. 이와 유사한 문제가 꽤 있다. 대표적으로 벽 부수고 이동하기 문제이다. (검색 ㄱㄱ!)

벽 부수고 이동하기와 문제 조건이 거의 유사하다. 벽 부수고 이동하기 문제의 경우 벽을 부수는 행위를 할 수 있고, 말이 되고픈 원숭이 문제의 경우 말처럼 이동할 수 있는 것이다.

 

단순 BFS의 핵심은 어떤 지점에 도달했을 때 이전에 방문한 적이 없다면 그 경우가 최적의 경우인 것이다.

큐의 특성상 거리가 N인 노드들을 모두 처리한 후에 N+1인 노드들을 처리하기 때문이다. 즉 거리가 1인 노드들이 모두 처리가 끝나야 거리가 2인 노드들이 들어오므로 이전에 방문한 적이 없다면 거리가 제일 작은 최적인 것이다.

 

하지만, 이 문제에서는 어떤 지점에 나중에 도달한 경우라도 최적인지 알 수 없다. 말처럼 이동하는 경우에 제한이 있기 때문이다. 따라서 어떤 지점에 도달했을 때 말처럼 이동한 횟수를 모두 따로 처리할 것이다.

배열을 3차원으로 확장해 생각해보자. board[i][j][k] 는 board[i][j] 지점에 도달한 경우 중, 말처럼 이동한 횟수가 k번인 경우이다.

코드

  • 좌표는 3차원이기 때문에 pair 자료형이 아니라 struct를 이용한다.
  • 이동하는 경우인 di, dj 배열은 4 방향이 아니라 말처럼 이동하는 경우인 8방향을 포함한 12방향이다. 단, 말처럼 이동하는 경우(배열 인덱스 0~7)는 더 이상 이동할 수 없을 수도 있기 때문에 예외처리를 해야 한다.
  • 결과적인 답은 dist[H-1][W-1][?] 부분을 전부 봐야 한다. 말처럼 이동한 횟수가 어찌됐든 도달한 경우를 모두 탐색해 최솟값이 답이다.
  • BFS는 처리 과정이 암기가 될 정도로 숙달되어 있어야 한다. 다음 게시물의 pesudo code는 바로바로 나올 정도로 익숙해지는 것이 좋다. https://morenow.tistory.com/37
#include <bits/stdc++.h>
using namespace std;
int board[201][201];
int dist[201][201][31];
int di[12] = {-2, -1, 1, 2, 2, 1 ,-1, -2, -1, 0, 1, 0};
int dj[12] = {1, 2, 2, 1, -1, -2, -2, -1, 0, 1, 0, -1};
int K, W, H, ans = 987654321;
struct pos {
int i, j, k;
};
void input() {
cin >> K >> W >> H;
for (int i = 0; i < H; i++) {
for (int j = 0; j < W; j++) {
cin >> board[i][j];
}
}
}
int main(void) {
ios::sync_with_stdio(0);
cin.tie(0);
input();
for (int i = 0; i < H; i++)
for (int j = 0; j < W; j++)
fill(dist[i][j], dist[i][j] + K+1, -1);
queue<pos> q;
q.push(pos{0, 0, 0});
dist[0][0][0] = 0;
while (!q.empty()) {
int ci = q.front().i;
int cj = q.front().j;
int ck = q.front().k;
q.pop();
for (int a = 0; a < 12; a++) {
int ni = ci + di[a];
int nj = cj + dj[a];
int nk = ck + ((a < 8) ? 1 : 0);
if (nk > K && a < 8) continue;
if (ni < 0 || ni >= H || nj < 0 || nj >= W || dist[ni][nj][nk] != -1 || board[ni][nj] == 1)
continue;
q.push(pos{ni, nj, nk});
dist[ni][nj][nk] = dist[ci][cj][ck] + 1;
}
}
for (int i = 0; i <= K; i++) {
if (dist[H-1][W-1][i] == -1) continue;
ans = min (ans, dist[H-1][W-1][i]);
}
if (ans == 987654321) cout << -1;
else cout << ans;
return 0;
}

'Baekjoon Online Judge' 카테고리의 다른 글

[BOJ] 1339 : 단어 수학 (C++)  (0) 2023.09.03
[BOJ] 3055 : 탈출 (C++)  (0) 2023.08.30
[BOJ] 2140: 지뢰찾기 (C++)  (0) 2023.08.29
[BOJ] 16236: 아기 상어 (C++)  (0) 2023.08.29
[BOJ] 3109: 빵집 (C++)  (0) 2023.08.28
  • 알고리즘 아이디어
  • 코드
'Baekjoon Online Judge' 카테고리의 다른 글
  • [BOJ] 1339 : 단어 수학 (C++)
  • [BOJ] 3055 : 탈출 (C++)
  • [BOJ] 2140: 지뢰찾기 (C++)
  • [BOJ] 16236: 아기 상어 (C++)
morenow
morenow

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.