(문제)
13460: Marble Escape 2(acmicpc.net)
13460호: 마블 이스케이프 2
첫 번째 줄에는 보드의 수직 및 수평 치수를 나타내는 두 개의 정수 N과 M(3 ≤ N, M ≤ 10)이 주어집니다. 다음 N 줄에는 보드의 모양을 나타내는 길이 M의 문자열이 포함됩니다. 이 문자열은 ‘.’, ‘#’, ‘O’, ‘R’, ‘B’입니다.
www.acmicpc.net
(문제 해결)
Marble Escape 1과 비슷한 문제인데, 구슬이 이동한 횟수가 추가되었습니다. 해당 부분에 대한 변수를 하나 더 생성하여 문제를 풀어보도록 하겠습니다.
bfs를 이용하면 쉽게 풀 수 있는 문제인데, 문제에서는 비엣젯을 사용할 필요가 없기 때문에 계산을 뺀다.
(회고)
비용을 초기화하는 부분을 잊어버렸는데, 틀렸습니다. 미리 조심하세요.
(암호)
#include <iostream>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
int dx(4) = {1,0,-1,0};
int dy(4) = {0,1,0,-1};
int board(20)(20);
int n,m;
//x좌표, y좌표, count는 현재 구슬이 몇번 상하좌우를 했는지 저장, cost는 구슬이 현재위치에서 다음위치까지의 거리.
struct bead{
int x;
int y;
int count;
int cost;
};
//구슬 2개
queue<bead> red;
queue<bead> blue;
//벽에 도달한다면 true 리턴
bool reachWall(int x, int y){
return x<0 or x>= n or y<0 or y>= m;
}
//계속해서 해당 방향으로 직진.
bead straight(bead answer, int dir){
int x = answer.x;
int y = answer.y;
int cost = answer.cost;
while(true){
cost++;
x += dx(dir);
y += dy(dir);
if(board(x)(y) == 1){
answer.x = x;
answer.y = y;
answer.cost = cost;
return answer;
}
//만일 벽에 도달했다면
if(board(x)(y) == -1 or reachWall(x,y)){
//벽에 도달한거니까 현재 왔던길을 1번 빼주자.
answer.x = x - dx(dir);
answer.y = y - dy(dir);
answer.cost = cost;
return answer;
}
}
// return answer;
}
int bfs(){
//10번 이하로 움직이기.
while(red.front().count < 10 || blue.front().count < 10){
bead curRed = red.front();
bead curBlue = blue.front();
//이때 초기화 하지 않으면 계속 cost가 추가될수 있고 그러면 이전 cost값을 더하면서 cost의 비교에서 문제가 생길수 있다.
curRed.cost = 0;
curBlue.cost = 0;
red.pop();
blue.pop();
for(int i = 0;i<4;i++){
bead nextRed = curRed;
bead nextBlue = curBlue;
nextBlue = straight(curBlue,i);
nextRed = straight(curRed,i);
//구슬을 움직였으니 다음 구슬에는 1번 움직였다는 것을 메모해주자.
nextBlue.count = curBlue.count + 1;
nextRed.count = curRed.count + 1;
int blueX = nextBlue.x;
int blueY = nextBlue.y;
int redX = nextRed.x;
int redY = nextRed.y;
//1. blue가 들어간다면.
if(board(blueX)(blueY) == 1){
continue;
}
//2. blue는 이미 뺐으니 red가 들어간다면 정답 처리해주자.
if(board(redX)(redY) == 1){
return nextRed.count;
}
//3. 둘이 겹친다면 거리 파악을 하고 더 멀리 온 구슬을 1번 뒤로 돌리자.
if(nextBlue.x == nextRed.x && nextBlue.y == nextRed.y){
if(nextBlue.cost > nextRed.cost){
nextBlue.x -= dx(i);
nextBlue.y -= dy(i);
}
else if(nextRed.cost > nextBlue.cost){
nextRed.x -= dx(i);
nextRed.y -= dy(i);
}
}
red.push(nextRed);
blue.push(nextBlue);
}
}
return -1;
}
int main(){
cin>>n>>m;
for(int i = 0;i<n;i++){
for(int j = 0;j<m;j++){
char temp;
cin>>temp;
if(temp == '#'){
//벽은 -1
board(i)(j) = -1;
}
else if(temp == 'O'){
//골인지점.
board(i)(j) = 1;
}
else if(temp == 'R'){
bead temp;
temp.x = i;
temp.y = j;
temp.count = 0;
temp.cost = 0;
red.push(temp);
}
else if(temp == 'B'){
bead temp;
temp.x = i;
temp.y = j;
temp.count = 0;
temp.cost = 0;
blue.push(temp);
}
}
}
cout<<bfs()<<endl;
return 0;
}
