티스토리 뷰

728x90

문제

N×M의 행렬로 표현되는 맵이 있다. 맵에서 0은 이동할 수 있는 곳을 나타내고, 1은 이동할 수 없는 벽이 있는 곳을 나타낸다. 당신은 (1, 1)에서 (N, M)의 위치까지 이동하려 하는데, 이때 최단 경로로 이동하려 한다. 최단경로는 맵에서 가장 적은 개수의 칸을 지나는 경로를 말하는데, 이때 시작하는 칸과 끝나는 칸도 포함해서 센다. 이동하지 않고 같은 칸에 머물러있는 경우도 가능하다. 이 경우도 방문한 칸의 개수가 하나 늘어나는 것으로 생각해야 한다.

이번 문제에서는 낮과 밤이 번갈아가면서 등장한다. 가장 처음에 이동할 때는 낮이고, 한 번 이동할 때마다 낮과 밤이 바뀌게 된다. 이동하지 않고 같은 칸에 머무르는 경우에도 낮과 밤이 바뀌게 된다.

만약에 이동하는 도중에 벽을 부수고 이동하는 것이 좀 더 경로가 짧아진다면, 벽을 K개 까지 부수고 이동하여도 된다. 단, 벽은 낮에만 부술 수 있다.

한 칸에서 이동할 수 있는 칸은 상하좌우로 인접한 칸이다.

맵이 주어졌을 때, 최단 경로를 구해 내는 프로그램을 작성하시오.

 

입력

첫째 줄에 N(1 ≤ N ≤ 1,000), M(1 ≤ M ≤ 1,000), K(1 ≤ K ≤ 10)이 주어진다. 다음 N개의 줄에 M개의 숫자로 맵이 주어진다. (1, 1)과 (N, M)은 항상 0이라고 가정하자.

 

출력

첫째 줄에 최단 거리를 출력한다. 불가능할 때는 -1을 출력한다.

 

코드

#include <iostream>
#include <string>
#include <queue>

using namespace std;

struct pos
{
	int r;
	int c;
	int destroy;
	bool day;

	void init(int r, int c, int destroy, bool day)
	{
		this->r = r;
		this->c = c;
		this->destroy = destroy;
		this->day = day;
	}
};

int N;
int M;
int K;
int map[1001][1001];		// 지도
int dp[1001][1001][11][2];	// 최단 경로 및 방문여부
int d[] = {-1, 1, 0, 0};

// 좌표가 범위 내인지 확인
bool in_range(pos p)
{
	if (p.r < 1 || p.r > N || p.c < 1 || p.c > M)
		return false;
	return true;
}

int bfs()
{
	queue<pos> q;
	pos curr, next;
	int i;

	// 출발지 삽입, 출발지도 포함하므로 최단 경로는 1
	next.init(1, 1, 0, true);
	dp[next.r][next.c][next.destroy][next.day] = 1;
	q.push(next);
	while (!q.empty())
	{
		curr = q.front();
		q.pop();

		// 도착지인 경우 최단 경로를 리턴
		if (curr.r == N && curr.c == M)
		{
			return dp[curr.r][curr.c][curr.destroy][curr.day];
		}

		// 상하좌우에 대하여
		for (i = 0; i < 4; i++)
		{
			next.init(curr.r + d[i], curr.c + d[3 - i], curr.destroy, !curr.day);

			// 범위 밖이면 패스
			if (!in_range(next))
			{
				continue;
			}

			// 벽인 경우
			if (map[next.r][next.c])
			{
				// 더 이상 벽을 부술 수 없으면 패스
				if (curr.destroy >= K)
				{
					continue;
				}
				// 낮이면 벽을 부수고 이동함
				if (curr.day)
				{
					next.destroy++;
				}
				// 밤이면 이동하지 않고 머무름
				else
				{
					next.r -= d[i];
					next.c -= d[3 - i];
				}
			}

			// 이미 방문한 적이 있으면 패스
			if (dp[next.r][next.c][next.destroy][next.day])
			{
				continue;
			}

			// 최단 경로를 저장하고 큐에 삽입
			dp[next.r][next.c][next.destroy][next.day] = dp[curr.r][curr.c][curr.destroy][curr.day] + 1;
			q.push(next);
		}
	}

	// 도착지에 가지 못하는 경우
	return -1;
}

int main()
{
	int i, j;
	string s;

	cin >> N >> M >> K;
	for (i = 1; i <= N; i++)
	{
		cin >> s;
		for (j = 1; j <= M; j++)
		{
			map[i][j] = s[j - 1] - '0';
		}
	}
	cout << bfs() << endl;
	return 0;
}

 

이 문제는 아래 문제에서 낮과 밤이라는 부분만 추가된 것이다. 메모리 초과와 시간 초과를 피하기 위해서는 동일한 상황이 여러 번 확인되지 않아야 한다. 여기서 동일한 상황이란 큐에 삽입되는 값이 같은 경우를 의미한다.

 

[백준] 14442번 - 벽 부수고 이동하기 2 / C++

문제 N×M의 행렬로 표현되는 맵이 있다. 맵에서 0은 이동할 수 있는 곳을 나타내고, 1은 이동할 수 없는 벽이 있는 곳을 나타낸다. 당신은 (1, 1)에서 (N, M)의 위치까지 이동하려 하는데, 이때 최단

peachh.tistory.com

 

링크

 

16933번: 벽 부수고 이동하기 3

첫째 줄에 N(1 ≤ N ≤ 1,000), M(1 ≤ M ≤ 1,000), K(1 ≤ K ≤ 10)이 주어진다. 다음 N개의 줄에 M개의 숫자로 맵이 주어진다. (1, 1)과 (N, M)은 항상 0이라고 가정하자.

www.acmicpc.net

 

inbdni/Baekjoon

Contribute to inbdni/Baekjoon development by creating an account on GitHub.

github.com

 

728x90
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
공지사항
링크
Total
Today
Yesterday