본문 바로가기

백준

백준1600 - 말이 되고픈 원숭이

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

 

1600번: 말이 되고픈 원숭이

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

www.acmicpc.net

bfs를 이용하여 푼 문제이다. 조금 색다른 방법을 사용해서 풀었다.

 

우선 나이트를 이동한 횟수에 따라서 좌표방문여부를 체크하였다. 즉 3차원 배열을 써서 방문여부를 체크하였다. 예를 들어 visit[3][5][2] = true이면 (3, 5)까지 이동하는데 2번 나이트처럼 이동하여 도착하였다라는 의미이다.

 

bfs는 상하좌우, 나이트이동으로 다음 칸을 탐색하고 나이트처럼 이동한 횟수가 최대 나이트이동 횟수보다 적으면 나이트이동으로 탐색이 가능하고 그 외에는 상하좌우이동만 가능하다고 구현하였다. 마지막에 최소로 걸린 시간을 출력하면 된다.

 

#include <iostream>
#include <queue>
#define MAX 201	
#define INF 987654321
using namespace std;

//x, y좌표, k는 걸린 시간, t는 나이트 이동횟수
class Point {
public:
	int x, y, k, t;
	Point(int x, int y, int k, int t) {
		this->x = x;
		this->y = y;
		this->k = k;
		this->t = t;
	}
};

int W, H, n; //가로, 세로, 정해진 횟수
int mat[MAX][MAX]; //입력 받은 좌표 정보
bool d[MAX][MAX][31] = { false, }; //x, y까지 k번의 나이트 처럼 이동해서 방문한 기록
int small = -1; //도달하는게 가장 짧게 걸리는 시간

//상하좌우
int dx[] = { 1,-1,0,0 };
int dy[] = { 0,0,1,-1 };

//나이트 이동
int kx[] = { 2,-2,1,-1,2,-2,1,-1 };
int ky[] = { 1,1,2,2,-1,-1,-2,-2 };

//bfs 구현
void bfs(int x, int y, int k, int t) {
	queue<Point> q;
	q.push(Point(x, y, k, t));
	d[x][y][0] = true;

	while (!q.empty()) {
		x = q.front().x;
		y = q.front().y;
		k = q.front().k;
		t = q.front().t;
		q.pop();

		if (x == H && y == W) { //도착점에 도달하였으면
			small = k; //도착점 시간을 반환하고
			break; //탈출
		}

		//상하좌우 이동
		for (int i = 0; i < 4; i++) {
			int nx = x + dx[i];
			int ny = y + dy[i];

			if (1 <= nx && nx <= H && 1 <= ny && ny <= W && mat[nx][ny] == 0 && d[nx][ny][t] == false) { //유효범위이고 빈 공간이고 t번 이동한 나이트가 방문한 적 없으면
				q.push(Point(nx, ny, k + 1, t)); //큐에 다음 위치를 시간 + 1을 하여 삽입
				d[nx][ny][t] = true; //t번 이동한 나이트를 (nx, ny)에 방문처리
			}
		}

		//나이트 이동, 나이트 최대 이동 수를 넘기지 않았다면 나이트를 이동한다.
		if (t < n) {
			for (int i = 0; i < 8; i++) {
				int nx = x + kx[i];
				int ny = y + ky[i];

				if (1 <= nx && nx <= H && 1 <= ny && ny <= W && mat[nx][ny] == 0 && d[nx][ny][t + 1] == false) { //유효범위이고 빈 공간이고 t + 1번 이동한 나이트가 방문한 적 없으면
					q.push(Point(nx, ny, k + 1, t + 1)); //큐에 다음 위치를 시간 + 1, 나이트 이동 횟수 + 1을 하여 삽입
					d[nx][ny][t + 1] = true; //t + 1번 이동한 나이트를 (nx, ny)에 방문처리
				}
			}
		}
	}
}

int main() {
	cin >> n;
	cin >> W >> H;

	for (int i = 1; i <= H; i++) {
		for (int j = 1; j <= W; j++) {
			cin >> mat[i][j];
		}
	}

	bfs(1, 1, 0, 0); //시작점에서 끝점 찾아가기

	cout << small;
}

 

'백준' 카테고리의 다른 글

백준16509 - 장군  (0) 2020.03.16
백준14442 - 벽 부수고 이동하기 2  (0) 2020.03.14
백준17141 - 연구소 2  (0) 2020.03.12
백준2234 - 성곽  (0) 2020.03.11
백준10819 - 차이를 최대로  (0) 2020.03.10