오늘의 알고리즘

[C++] 백준 2206 벽 부수고 이동하기

하늘하늘 . 2022. 5. 25. 18:11
 
#include <iostream>
#include <string.h>
#include <vector>
#include <queue>
#include <tuple>
 
int graph[1001][1001] = {};
bool visit[1001][1001][2] = {};
int iDirX[4] = { 1,-1,0,0 };
int iDirY[4] = { 0,0,1,-1 };
 
int main()
{
	int N = 0;
	int M = 0;
 
	std::cin >> N >> M;
	std::string s = {};
	for (int i = 0; i < N; ++i)
	{
		std::cin >> s;
 
		for (int j = 0; j < M; ++j)
		{
			graph[i][j] = s[j] - '0';
		}
	}
 
	std::queue<std::tuple<int, bool, int, int>> que = {};
	que.push({1, false, 0, 0 });
	visit[0][0][0] = true;
 
	while (!que.empty())
	{
		int iCount = std::get<0>(que.front());
		bool bUse = std::get<1>(que.front());
		int iX = std::get<2>(que.front());
		int iY = std::get<3>(que.front());
		que.pop();
 
		if (iX == N -1 && iY == M - 1)
		{
			std::cout << iCount;
			return 0;
		}
 
		for (int i = 0; i < 4; ++i)
		{
			int iNextX = iX + iDirX[i];
			int iNextY = iY + iDirY[i];
 
			if (iNextX >= 0 && iNextX < N &&
				iNextY >= 0 && iNextY < M)
			{
				if (!graph[iNextX][iNextY] && !visit[iNextX][iNextY][1] && bUse)
				{
					visit[iNextX][iNextY][1] = true;
					que.push({ iCount + 1, bUse, iNextX, iNextY });
				}
 
				else if (graph[iNextX][iNextY] && !visit[iNextX][iNextY][0] && !bUse)
				{
					visit[iNextX][iNextY][1] = true;
					que.push({ iCount + 1, true, iNextX, iNextY });
				}
 
				else if (!graph[iNextX][iNextY] && !visit[iNextX][iNextY][0] && !bUse)
				{
					visit[iNextX][iNextY][0] = true;
					que.push({ iCount + 1, bUse, iNextX, iNextY });
				}
			}
		}
 
	}
 
	std::cout << -1;
	return 0;
}

1. 벽을 뚫을 때와 안뚫을 때를 나눠서 해야한다. ( 나누지 않고 계산을 한다면 벽이 지그재그로 생겼을 때 이미 갈 수 있는 곳을 이미 방문해버려서 못 들어가게 막을 수가 있다. ) 

 

2. 메모리 초과 조심 ( 방문은 무조건 que.push 이전에 해야한다. 그렇지 않으면 그 큐가 오기 전에 같은 곳에 여러 번 방문해서 메모리 초과가 일어난다. )