- 문제
- M x N인 지도에 1은 장애물, 0은 통로로 표시됨
- 시작점과 방향, 도착점과 방향이 주어짐
- 방향은 위 1, 오 2, 아 3, 왼 4로 주어짐
- 1턴에 이동 또는 90도 회전 동작을 할 수 있음
- 한방향으로의 직진 이동시에는 1턴으로 전부 이동이 가능함
- 시작점에서 도착점까지의 최소 동작 턴 수를 리턴
- 시도
- 방향 인자를 추가적으로 고민해야 하는 문제
- 이전에 풀었던 로보패스 문제 풀이를 기초로 변형해보자
- 이전 문제는 이동만 고려해서 생각보다 풀이는 간단했음
- 문제는 방향 전환 루틴, 회전이 한 방향으로만 이루어지는게 아니여서, 회전수가 적게 필요한 방향을 인지하고 그 방향으로 회전시켜야 함
- 처음으로는 상하좌우의 위치값이 범위 내인지, 범위 내라면 장애물인지 통로인지를 파악, 그리고 현재 위치에서 통로로 가는 방향의 값을 파악
- 통로의 값은 위쪽 통로이면 1, 오른쪽 통로이면 2
- 현재의 방향값에 따라 각각의 통로값이 대응하는 회전 값을 미리 계산해놓고 더해주는 방식으로 대응해보면 어떨까
- 현재 1, 상0,우1,하2,좌1
- 현재 2, 상1,우0,하1,좌2
- 현재 3, 상2,우1,하0,좌1
- 현재 4, 상1,우2,하1,좌0
- 위와 같은 대응 값을 갖는다
- 시작점을 1로 바꾸고 시작, 상하좌우의 값을 체크하면서 변경시켜가자
- 지도의 좌표값을 전부 변경시킨 후 도착 좌표의 값을 리턴하면 될 듯, 혹은 -1한 값을 해야할 수도 있겠음
- 문제의 조건 중 1가지를 놓치고 풀이하였음, 직진으로 이동할 때에는 1턴으로 전부 이동이 가능함
- 잘못 이해한 풀이로는 문제가 잘 해결되긴 하였음
- 차후 다시 조건에 맞춰 풀어야 할 것 같음
- 수도코드
const robotPath2 = function (room, src, sDir, dst, dDir) {
const mover = (m, n, now, cur, turn) => {
const [r,c] = now;
if (r < 0 || r >= m || c < 0 || c >= n) return;
if (room[r][c] === 0 || room[r][c] > turn) {room[r][c] = turn;}
else {return;}
if (cur === 1) {
mover(m, n, [r - 1, c], 1, turn + 1);
mover(m, n, [r, c + 1], 2, turn + 2);
mover(m, n, [r + 1, c], 3, turn + 3);
mover(m, n, [r, c - 1], 4, turn + 2);
}
if (cur === 2) {
mover(m, n, [r - 1, c], 1, turn + 2);
mover(m, n, [r, c + 1], 2, turn + 1);
mover(m, n, [r + 1, c], 3, turn + 2);
mover(m, n, [r, c - 1], 4, turn + 3);
}
if (cur === 3) {
mover(m, n, [r - 1, c], 1, turn + 3);
mover(m, n, [r, c + 1], 2, turn + 2);
mover(m, n, [r + 1, c], 3, turn + 1);
mover(m, n, [r, c - 1], 4, turn + 2);
}
if (cur === 4) {
mover(m, n, [r - 1, c], 1, turn + 2);
mover(m, n, [r, c + 1], 2, turn + 3);
mover(m, n, [r + 1, c], 3, turn + 2);
mover(m, n, [r, c - 1], 4, turn + 1);
}
}
mover(room.length, room[0].length, src, sDir, 1);
const [row, col] = dst;
return room[row][col] - 1;
};
- 레퍼런스
const robotPath2 = function (room, src, sDir, dst, dDir) {
const R = room.length;
const C = room[0].length;
const MOVES = [
[1, -1, 0],
[2, 0, 1],
[3, 1, 0],
[4, 0, -1],
];
const isValid = (row, col) => row >= 0 && row < R && col >= 0 && col < C;
const directions = [];
const dist = [];
for (let row = 0; row < R; row++) {
directions.push(Array(C).fill(0));
dist.push(Array(C).fill(Number.MAX_SAFE_INTEGER));
}
const queue = Array(R * C);
let front = 0;
let rear = 0;
const isEmpty = (queue) => front === rear;
const enQueue = (queue, pos) => {
queue[rear] = pos;
rear++;
};
const deQueue = (queue) => {
return queue[front++];
};
const [sRow, sCol] = src;
directions[sRow][sCol] = sDir;
dist[sRow][sCol] = 0;
const [dRow, dCol] = dst;
enQueue(queue, [sRow, sCol]);
while (isEmpty(queue) === false) {
const [row, col] = deQueue(queue);
const dir = directions[row][col];
for (move of MOVES) {
const [nDir, rDiff, cDiff] = move;
const nRow = row + rDiff;
const nCol = col + cDiff;
if (isValid(nRow, nCol) === false || room[nRow][nCol] === 1) continue;
const dDiff = Math.abs(nDir - dir);
let candidate;
if (dDiff === 0) {
candidate = dist[row][col] || 1;
} else if (dDiff === 2) {
candidate = dist[row][col] + 3;
} else {
candidate = dist[row][col] + 2;
}
if (nRow === dRow && nCol === dCol) {
const dDiff = Math.abs(nDir - dDir);
if (dDiff === 0) {
candidate = candidate;
} else if (dDiff === 2) {
candidate = candidate + 2;
} else {
candidate = candidate + 1;
}
}
if (candidate < dist[nRow][nCol]) {
enQueue(queue, [nRow, nCol]);
dist[nRow][nCol] = candidate;
directions[nRow][nCol] = nDir;
}
}
}
return dist[dRow][dCol];
};