문제 링크
https://www.acmicpc.net/problem/25307
문제
시루는 부모님과 함께 백화점에 갔다. 부모님은 쇼핑할 것이 많기 때문에 여러 곳을 돌아다녀야 하고, 시루는 부모님과 함께 걸어다니는 것이 너무 힘들어서 의자에 앉아서 쉬려고 한다.
백화점은 세로 길이가 N, 가로 길이가 M인 격자 형태이고, 상하좌우로 인접한 칸으로 이동할 때마다 1 만큼의 체력을 소모한다. 시루는 현재 위치에서 출발해 백화점 곳곳에 있는 의자 중 하나를 찾아가서 앉으려고 한다. 시루는 백화점 밖으로 나가면 부모님께 혼나기 때문에 백화점 밖으로 나갈 수 없다.
백화점에는 건물을 지탱하기 위한 기둥과 옷을 전시하기 위한 마네킹이 있다. 시루는 기둥이 있는 칸으로 이동하지 못하고, 마네킹을 무서워하기 때문에 마네킹과 거리가 K 이하인 칸은 사용하지 않으려고 한다. 이때 두 칸 (rx, cx), (ry, cy)의 거리는 |rx−ry|+|cx−cy|이다. 단, 시루가 출발할 때는 부모님과 함께 있기 때문에, 출발 지점과 마네킹과의 거리가 K 이하가 되어도 출발할 수 있다.
시루는 다리가 너무 아프기 때문에 체력 소모를 최소화하면서 의자까지 찾아가려고 한다. 시루가 소모하는 체력의 최솟값을 구해보자.
입력
첫째 줄에 백화점의 세로 길이, 가로 길이, 마네킹과 떨어져야 하는 거리를 의미하는 정수 N, M, K가 공백으로 구분되어 주어진다. (1 ≤ N, M ≤ 2,000, 0 ≤ K ≤ 4,000)
둘째 줄부터 N개의 줄에 각각 M개씩 위에서부터 차례로 백화점의 상태가 주어진다. 아무것도 없는 칸은 0, 기둥이 있는 칸은 1, 의자가 있는 칸은 2, 마네킹이 있는 칸은 3, 시루의 시작 위치는 4로 주어진다. 시루의 시작 위치는 정확히 한 번 주어지고, 해당 위치에 기둥, 의자, 마네킹이 존재하지 않는다.
출력
시루가 의자를 찾아갈 수 있다면 시루가 소모하는 체력의 최솟값을 출력한다.
만약 의자를 찾아갈 수 없다면 -1을 출력한다.
예제 입력 1
5 5 1
0 0 0 0 4
0 0 0 1 0
0 0 0 0 3
0 0 0 1 0
0 0 0 0 2
예제 출력 1
8
예제 입력 2
5 5 2
0 0 0 0 4
0 0 0 1 0
0 0 0 0 3
0 0 0 1 0
0 0 0 0 2
예제 출력 2
-1
예제 입력 3
5 5 2
2 0 0 0 4
0 0 0 1 0
0 0 0 0 3
0 0 0 1 0
0 0 0 0 0
예제 출력 3
4
예제 입력 4
5 5 0
0 0 0 0 4
0 0 0 1 0
0 0 0 0 3
0 0 0 1 0
0 0 0 0 0
예제 출력 4
-1
알고리즘 분류
- 그래프 탐색
풀이
먼저 접근하면 안 되는 칸을 기록해야 한다. 마네킹들의 현재 좌표를 큐에 넣고 BFS를 수행하며, 마네킹과 최대 K만큼 떨어진 칸들을 모두 체크해둔다.
그리고 시루의 현재 위치에서 시작해서 BFS를 수행한다. 이 때, 기둥이나 미리 기록해 둔 칸들을 제외한 칸에만 접근할 수 있으며, 의자가 있는 칸까지 갈 수 있는 최소의 시간을 출력한다. 의자가 있는 칸에 접근이 불가능하다면 -1을 출력한다.
코드
#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <algorithm>
#define MAX 2001
#define FASTIO cin.tie(0); cout.tie(0); ios::sync_with_stdio(false);
using namespace std;
int N, M, K;
int MAP[MAX][MAX];
bool Banned[MAX][MAX];
bool visited[MAX][MAX];
pair<int, int> Start;
queue<pair<pair<int, int>, int> > Q1;
int MoveY[4] = { -1,0,1,0 };
int MoveX[4] = { 0,-1,0,1 };
void input() {
cin >> N >> M >> K;
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
cin >> MAP[i][j];
if (MAP[i][j] == 3) {
Banned[i][j] = true;
Q1.push(make_pair(make_pair(i, j), K));
}
else if (MAP[i][j] == 4) {
MAP[i][j] = 0;
Start = make_pair(i, j);
}
}
}
}
void settings() {
while (!Q1.empty()) {
int NowY = Q1.front().first.first;
int NowX = Q1.front().first.second;
int NowT = Q1.front().second;
Q1.pop();
if (NowT == 0) {
continue;
}
for (int i = 0; i < 4; i++) {
int NextY = NowY + MoveY[i];
int NextX = NowX + MoveX[i];
if ((NextY >= 0) && (NextY < N) && (NextX >= 0) && (NextX < M) && !Banned[NextY][NextX]) {
Banned[NextY][NextX] = true;
Q1.push(make_pair(make_pair(NextY, NextX), NowT - 1));
}
}
};
Banned[Start.first][Start.second] = false;
}
int BFS() {
queue<pair<pair<int, int>, int> > Q;
visited[Start.first][Start.second] = true;
Q.push(make_pair(make_pair(Start.first, Start.second), 0));
while (!Q.empty()) {
int NowY = Q.front().first.first;
int NowX = Q.front().first.second;
int NowT = Q.front().second;
Q.pop();
if (MAP[NowY][NowX] == 2) {
return NowT;
}
for (int i = 0; i < 4; i++) {
int NextY = NowY + MoveY[i];
int NextX = NowX + MoveX[i];
if ((NextY >= 0) && (NextY < N) && (NextX >= 0) && (NextX < M)) {
if ((MAP[NextY][NextX] == 0) || (MAP[NextY][NextX] == 2)) {
if (!Banned[NextY][NextX]) {
if (!visited[NextY][NextX]) {
visited[NextY][NextX] = true;
Q.push(make_pair(make_pair(NextY, NextX), NowT + 1));
}
}
}
}
}
};
return -1;
}
void find_Answer() {
cout << BFS() << "\n";
}
int main() {
FASTIO
input();
settings();
find_Answer();
return 0;
}
'BOJ > Gold' 카테고리의 다른 글
[BOJ/Gold 2] 백준 16934 게임 닉네임(C++) (0) | 2023.04.06 |
---|---|
[BOJ/Gold 3] 백준 20182 골목 대장 호석 - 효율성 1(C++) (0) | 2023.04.05 |
[BOJ/Gold 5] 백준 17394 핑거 스냅(C++) (0) | 2023.03.30 |
[BOJ/Gold 5] 백준 23048 자연수 색칠하기(C++) (0) | 2023.03.30 |
[BOJ/Gold 4] 백준 15961 회전 초밥(C++) (0) | 2023.03.29 |