Algorithm

백준 13460번 삼성기출 구술탈출2

asung123 2020. 4. 20. 13:42

 

문제의 알고리즘 자체는 어려운편은 아니지만, 예외 케이스가 많고 기저 사건이 다양하기 때문에 문제를 잘읽고

코드는 최대한, 실수가 나지 않게끔 길어지더라도, 명확하게 분류해서 잘짜는게 중요한듯 합니다.

 

알고리즘은 기본적인 BFS 최단 문제입니다.

 

#include<iostream>
#include<vector>
#include<algorithm>
#include<string>
#include<queue>
using namespace std;

int N, M;
string Map[10];
int dx[4] = {-1,1,0,0};
int dy[4] = {0,0,-1,1};
int oy, ox;
int bx, by;
int rx, ry;

struct pos {
	int bx, by;
	int rx, ry;
	int cnt;
	pos(int by, int bx,int ry,int rx, int cnt) :by(by), bx(bx), ry(ry), rx(rx),cnt(cnt) {}
};

bool visit[10][10][10][10];

int BFS() {
	queue<pos> q;
	q.push(pos(by, bx, ry, rx,0));

	while (!q.empty()) {
        // queue에서 pop
		int cpos[4] = {q.front().by, q.front().bx, q.front().ry, q.front().rx};
		int cnt = q.front().cnt; q.pop();
        
		if (cnt > 10) break; //횟수 제한 초과
        
		visit[cpos[0]][cpos[1]][cpos[2]][cpos[3]] = true;
        
        //정답
		if (cpos[2] == oy && cpos[3] == ox) return cnt;
		
        // 상 하 좌 우
		for (int i = 0; i < 4; i++) {
			int npos[4] = { cpos[0],cpos[1],cpos[2],cpos[3] }; //next pos
            
            // 0에 빠졌는지 flag
			bool flag = true;
			bool flag2 = true;
            
            //blue가 쭉 움직인다.		
			while (Map[npos[0]+dy[i]][npos[1]+dx[i]] != '#' && flag) {
				npos[0] += dy[i];
				npos[1] += dx[i];
				if (Map[npos[0]][npos[1]] == 'O') flag = false;
			}

		    
			//red가 쭉움직인다.
			while (Map[npos[2] + dy[i]][npos[3] + dx[i]] != '#' && flag2) {
				npos[2] += dy[i];
				npos[3] += dx[i];
				if (Map[npos[2]][npos[3]] == 'O') flag2 = false;
			}

			//블루가 구멍에 빠져버렸으면 이번 경우의 수는 스킵한다.
			if (!flag) continue;
		
			if (npos[0] == npos[2] && npos[1] == npos[3]) {
				// red blue 위치가 같은 경우
				// 원래 순서와 움직인 방향에 따라 red blue 순서를 재배치
				switch (i)
				{
				case 0:
					if (cpos[1] < cpos[3]) npos[3] -= dx[i];
					else npos[1] -= dx[i];
					break;
				case 1:
					if (cpos[1] < cpos[3]) npos[1] -= dx[i];
					else npos[3] -= dx[i];
					break;
				case 2:
					if (cpos[0] < cpos[2]) npos[2] -= dy[i];
					else npos[0] -= dy[i];
					break;
				case 3:
					if (cpos[0] < cpos[2]) npos[0] -= dy[i];
					else npos[2] -= dy[i];
					break;
				}
			}
			
			if (!visit[npos[0]][npos[1]][npos[2]][npos[3]]) {
				q.push(pos(npos[0], npos[1], npos[2], npos[3], cnt + 1));
			}
		}
	}
	return -1;
}

int main() {
	ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);

	cin >> N >> M;

	for (int i = 0; i < N; i++) {
		cin >> Map[i];
	}
    
    //맵을 흝으며, B,R,O의 좌표를 저장
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < M; j++) {
			char tmp = Map[i][j];
			if (tmp == 'B') {
				by = i; bx = j;
			}
			if (tmp == 'R') {
				ry = i; rx = j;
			}
			if (tmp == 'O') {
				oy = i; ox = j;
			}
		}
	}

	cout << BFS();

}

이렇게 예외케이스가 많은경우, 

switch문을 사용하여 이쁘게 정리하는게 코드를 눈으로 볼 때 좋았던거 같습니다.

 

저는 쉽게 가려고 npos[4] , cpos[4] 등 배열을 그냥 썼는데,  변수의 의미가 제대로 보이지 않아 실수하기 쉬웠습니다.

이런 복잡한 케이스를 가지는 문제들은 Blue_xPos, Blue_yPos 등  정확한 변수이름을 써서 코딩하는 것이 실수를 줄일 수 있습니다.