Thief of Wealth
시간 제한메모리 제한제출정답맞은 사람정답 비율
2 초256 MB129102476142716.188%

문제

동물원에서 막 탈출한 원숭이 한 마리가 세상구경을 하고 있다. 그 녀석은 말(Horse)이 되기를 간절히 원했다. 그래서 그는 말의 움직임을 유심히 살펴보고 그대로 따라 하기로 하였다. 말은 말이다. 말은 격자판에서 체스의 나이트와 같은 이동방식을 가진다. 다음 그림에 말의 이동방법이 나타나있다. x표시한 곳으로 말이 갈 수 있다는 뜻이다. 참고로 말은 장애물을 뛰어넘을 수 있다.

 x x 
x   x
    
x   x
 x x 

근데 원숭이는 한 가지 착각하고 있는 것이 있다. 말은 저렇게 움직일 수 있지만 원숭이는 능력이 부족해서 총 K번만 위와 같이 움직일 수 있고, 그 외에는 그냥 인접한 칸으로만 움직일 수 있다. 대각선 방향은 인접한 칸에 포함되지 않는다.

이제 원숭이는 머나먼 여행길을 떠난다. 격자판의 맨 왼쪽 위에서 시작해서 맨 오른쪽 아래까지 가야한다. 인접한 네 방향으로 한 번 움직이는 것, 말의 움직임으로 한 번 움직이는 것, 모두 한 번의 동작으로 친다. 격자판이 주어졌을 때, 원숭이가 최소한의 동작으로 시작지점에서 도착지점까지 갈 수 있는 방법을 알아내는 프로그램을 작성하시오.

입력

첫째 줄에 자연수 K가 주어진다. 둘째 줄에 격자판의 가로길이 W, 세로길이 H가 주어진다. 그 다음 H줄에 걸쳐 W개의 숫자가 주어지는데, 0은 아무것도 없는 평지, 1은 장애물을 뜻한다. 장애물이 있는 곳으로는 이동할 수 없다. 시작점과 도착점은 항상 평지이다. W와 H는 1이상 200이하의 자연수이고, K는 0이상 30이하의 정수이다.

출력

첫째 줄에 원숭이의 동작수의 최솟값을 출력한다. 시작점에서 도착점까지 갈 수 없는 경우엔 -1을 출력한다.



이 문제는 기존 bfs에다가 앞서 포스팅한 벽부수고 이동하기의 확장문제이다.
그래서 처음에 벽부수고 이동하기 처럼 푼다는 것을 깨닫는게 시간을 소모했는데,
그것을 구현하고 나서도 계속 틀렸다.
바로, W, H인 가로 세로를 반대로 받아왔고, 반대로 비교하고 있었기 때문이다.
반례체크해보면서, 가로세로 잘못입력한 케이스들이 종종 보이길래 나는 안그런건줄 알았는데,
알고보니 10번째 시도동안 가로세로를 제대로 받아오고, 체크를 거꾸로 하고 있었던 것이다..

그냥 bfs에다가 말처럼이동가능한 횟수만큼의 차원을 만들어서 체크를 해주면 되었다.

#include <iostream>
#include <cstdlib>
#include <queue>
#include <algorithm>
#include <cstring>
using namespace std;

int nomal_x_direction[4]= {-1,1,0,0};
int nomal_y_direction[4]= {0,0,-1,1};

int skill_x_direction[8] = {-1,-2,-2,-1,1,2,2,1};
int skill_y_direction[8] = {-2,-1,1,2,-2,-1,1,2};

int K,W,H; // K는 말처럼 이동가능한 횟수, W는 가로길이, H는 세로길이

int Zoo[201][201]; //1은 장애물, 0은 그냥 평지
int visited[31][201][201];
struct Data{
int x;
int y;
int remainedSkill;
Data(int a, int b, int r):x(a),y(b),remainedSkill(r){}
};
int bfs(Data d);
int main(){
freopen("input.txt","r",stdin);
ios::sync_with_stdio(false);
cin.tie(0);

memset(visited, false, sizeof(visited));
memset(Zoo, 0, sizeof(Zoo));
cin>>K>>W>>H;
int temp;
int i;
for(int j=0; j<H; ++j){
for(int k=0; k<W; ++k){
cin>> temp;
Zoo[j][k] = temp;
}
}
cout<<bfs(Data(0,0,K));
//cout<<"\n";
/*for(int i=0; i<H; ++i){
for(int j=0; j<W; ++j){
cout<<visited[K][i][j]<<" ";
}
cout<<"\n";
}*/

return 0;
}

int bfs(Data d){
queue<Data> que;
que.push(d);
visited[d.remainedSkill][d.x][d.y] = true;
int step_size=0;
int total_step_size=0;
Data tmp(-1,-1,-1);
while( !que.empty() ){
step_size = que.size();
for(int s=0; s<step_size; ++s){
tmp = que.front();
que.pop();
if( (tmp.y == W-1) && (tmp.x==H-1) ){
return total_step_size;
}

for(int i=0; i<4; ++i){
//일반 탐색
if(
(nomal_x_direction[i]+tmp.x)>=0 &&
(nomal_x_direction[i]+tmp.x)<H &&
(nomal_y_direction[i]+tmp.y)>=0 &&
(nomal_y_direction[i]+tmp.y)<W &&
visited[tmp.remainedSkill][nomal_x_direction[i]+tmp.x][nomal_y_direction[i]+tmp.y] == false &&
Zoo[nomal_x_direction[i]+tmp.x][nomal_y_direction[i]+tmp.y] == 0
){
que.push(Data(nomal_x_direction[i]+tmp.x, nomal_y_direction[i]+tmp.y, tmp.remainedSkill));
visited[tmp.remainedSkill][nomal_x_direction[i]+tmp.x][nomal_y_direction[i]+tmp.y] = true;
//cout<<i<<"\n";
//cout<<nomal_x_direction[i]<<" <> "<<tmp.x<<"\n";
//cout<<nomal_y_direction[i]<<" <> "<<tmp.y<<"\n";
//cout<<"\n추가: "<<nomal_x_direction[i]+tmp.x<<" "<<nomal_y_direction[i]+tmp.y<<"\n";
}
}
if( tmp.remainedSkill > 0 ){
//말처럼 이동할 수 있을떄
for(int i=0; i<8; ++i){
if(
(skill_x_direction[i]+tmp.x)>=0 &&
(skill_x_direction[i]+tmp.x)<H &&
(skill_y_direction[i]+tmp.y)>=0 &&
(skill_y_direction[i]+tmp.y)<W &&
visited[tmp.remainedSkill-1][skill_x_direction[i]+tmp.x][skill_y_direction[i]+tmp.y] == false &&
Zoo[skill_x_direction[i]+tmp.x][skill_y_direction[i]+tmp.y] == 0
){
que.push(Data(skill_x_direction[i]+tmp.x, skill_y_direction[i]+tmp.y, tmp.remainedSkill-1));
visited[tmp.remainedSkill-1][skill_x_direction[i]+tmp.x][skill_y_direction[i]+tmp.y] = true;
}
}
}
}
total_step_size++;
}
return -1; //도착하지 못한 채로 갈 수 있는 곳 모두 탐색완료
}



'개발 > 알고리즘' 카테고리의 다른 글

Greedy 기법  (0) 2019.05.09
1922 네트워크 연결 ( Prim algorithm )  (0) 2019.05.09
13913 숨바꼭질4  (0) 2019.04.28
13549 숨바꼭질3  (1) 2019.04.27
6594 Dungeon Master  (0) 2019.04.25
profile on loading

Loading...