82 lines
2.0 KiB
TypeScript
82 lines
2.0 KiB
TypeScript
export {};
|
|
|
|
type tuple = [number, number, number, boolean];
|
|
|
|
class Deque <T> {
|
|
private enqueue: T[];
|
|
private dequeue: T[];
|
|
|
|
constructor() {
|
|
this.enqueue = [];
|
|
this.dequeue = [];
|
|
}
|
|
|
|
public isEmpty(): boolean {
|
|
return (this.enqueue.length === 0 && this.dequeue.length === 0);
|
|
}
|
|
|
|
public push(data: T) {
|
|
this.enqueue.push(data);
|
|
}
|
|
|
|
public popLeft(): T | undefined {
|
|
if(this.isEmpty()) {
|
|
return undefined;
|
|
}
|
|
|
|
if(this.dequeue.length === 0) {
|
|
this.enqueue.reverse();
|
|
this.dequeue = this.enqueue;
|
|
this.enqueue = [];
|
|
}
|
|
|
|
let value: T = this.dequeue.pop();
|
|
return value;
|
|
}
|
|
|
|
// 필요시 일반적인 pop과 왼쪽 삽입 매서드도 구현해서 사용하면 됩니다.
|
|
}
|
|
|
|
const input = require("fs").readFileSync(0).toString().trim().split('\n');
|
|
const [N, M] = input[0].split(' ').map(Number);
|
|
|
|
let mapData: number[][] = [];
|
|
for(let i=1; i<=N; i++) mapData.push(input[i].split('').map(Number));
|
|
|
|
let visited: boolean[][][] = Array.from({length: N}, () => Array.from({length: M}, () => [false, false]));
|
|
visited[0][0] = [true, true];
|
|
let dq = new Deque<tuple>();
|
|
dq.push([0,0,1,false]);
|
|
let result: number = -1;
|
|
const dx = [1,-1,0,0];
|
|
const dy = [0,0,1,-1];
|
|
|
|
while(!dq.isEmpty()) {
|
|
const [cx, cy, cd, breakBlock]: tuple = dq.popLeft();
|
|
|
|
if(cx === M-1 && cy === N-1) {
|
|
result = cd;
|
|
break;
|
|
}
|
|
|
|
for(let i=0; i<4; i++) {
|
|
const [nx, ny]: number[] = [cx + dx[i], cy + dy[i]];
|
|
|
|
if(ny < 0 || ny >= N || nx < 0 || nx >= M) continue;
|
|
|
|
const isWall = mapData[ny][nx] === 1;
|
|
|
|
if(isWall && breakBlock) continue;
|
|
|
|
const nextBreakBlock: boolean = breakBlock || isWall;
|
|
const blockState: number = nextBreakBlock ? 1 : 0;
|
|
|
|
if(!visited[ny][nx][blockState]) {
|
|
dq.push([nx, ny, cd+1, nextBreakBlock]);
|
|
visited[ny][nx][blockState] = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
console.log(result);
|