어른 상어가 마법사가 되었고, 파이어볼을 배웠다.
마법사 상어가 크기가 N×N인 격자에 파이어볼 M개를 발사했다. 가장 처음에 파이어볼은 각자 위치에서 이동을 대기하고 있다. i번 파이어볼의 위치는 (ri, ci), 질량은 mi이고, 방향은 di, 속력은 si이다. 위치 (r, c)는 r행 c열을 의미한다.
격자의 행과 열은 1번부터 N번까지 번호가 매겨져 있고, 1번 행은 N번과 연결되어 있고, 1번 열은 N번 열과 연결되어 있다.
파이어볼의 방향은 어떤 칸과 인접한 8개의 칸의 방향을 의미하며, 정수로는 다음과 같다.
7 | 0 | 1 |
6 | 2 | |
5 | 4 | 3 |
마법사 상어가 모든 파이어볼에게 이동을 명령하면 다음이 일들이 일어난다.
- 모든 파이어볼이 자신의 방향 di로 속력 si칸 만큼 이동한다.
- 이동하는 중에는 같은 칸에 여러 개의 파이어볼이 있을 수도 있다.
- 이동이 모두 끝난 뒤, 2개 이상의 파이어볼이 있는 칸에서는 다음과 같은 일이 일어난다.
- 같은 칸에 있는 파이어볼은 모두 하나로 합쳐진다.
- 파이어볼은 4개의 파이어볼로 나누어진다.
- 나누어진 파이어볼의 질량, 속력, 방향은 다음과 같다.
- 질량은 ⌊(합쳐진 파이어볼 질량의 합)/5⌋이다.
- 속력은 ⌊(합쳐진 파이어볼 속력의 합)/(합쳐진 파이어볼의 개수)⌋이다.
- 합쳐지는 파이어볼의 방향이 모두 홀수이거나 모두 짝수이면, 방향은 0, 2, 4, 6이 되고, 그렇지 않으면 1, 3, 5, 7이 된다.
- 질량이 0인 파이어볼은 소멸되어 없어진다.
마법사 상어가 이동을 K번 명령한 후, 남아있는 파이어볼 질량의 합을 구해보자.
====
문제 분석
문제에 나와있는 대로 구현을 하면 되는데 주의할 점은
1 . 속력의 범위가 n까지가 아닌 1000이하 라는 것.
2. 행과 열은 각각 1과 n이 연결됐다는 것.
따라서 다음으로 이동할 위치를 지정할 때 모듈 연산을 해줘야한다.
또한 파이어볼의 위치가 계속 바뀌므로 그래프를 직접 탐색하기보다 위치를 담고 있는 객체를 만들어서 키에 좌표를 두고 그 값에 좌표에 담길 파이어볼의 넘버를 넣어줄 것이다. 각 턴마다 동작을 수행할 dfs를 만들어줬다.
포지션 별로 담겨진 파이어볼에서 합체 후 4개로 나눠지므로 이들을 넣어줄 newInfo를 만들어주고
이 배열을 통해 새롭게 수행 할 dfs를 다시 호출해주면 된다.
정답 코드
const dx = [-1, -1, 0, 1, 1, 1, 0, -1];
const dy = [0, 1, 1, 1, 0, -1, -1, -1];
const main = (n, m, k, ballInfos) => {
let info = ballInfos.map((v) => [...v]);
const dfs = (ballInfo, turn) => {
if (turn === k) {
console.log(ballInfo.reduce((acc, cur) => acc + cur[2], 0));
process.exit(0);
}
const position = {};
for (let ballNumber = 0; ballNumber < ballInfo.length; ballNumber++) {
const [x, y, m, s, d] = ballInfo[ballNumber];
let nx = x + dx[d] * s;
let ny = y + dy[d] * s;
if (nx <= 0) nx = n - (Math.abs(nx) % n);
if (ny <= 0) ny = n - (Math.abs(ny) % n);
if (nx > n) {
nx = nx % n;
if (nx === 0) nx = n;
}
if (ny > n) {
ny = ny % n;
if (ny === 0) ny = n;
}
position[`${nx}-${ny}`] = [
...(position[`${nx}-${ny}`] || []),
ballNumber,
];
ballInfo[ballNumber][0] = nx;
ballInfo[ballNumber][1] = ny;
}
const newInfo = [];
for (const keys of Object.keys(position)) {
const [i, j] = keys.split('-');
if (position[keys].length === 1) {
const [x, y, m, s, dir] = ballInfo[position[keys][0]];
newInfo.push([+i, +j, m, s, dir]);
} else {
const mess = Math.floor(
position[keys].reduce(
(acc, cur) => acc + ballInfo[cur][2],
0
) / 5
);
if (mess === 0) continue;
const speed = Math.floor(
position[keys].reduce(
(acc, cur) => acc + ballInfo[cur][3],
0
) / position[keys].length
);
const firstNum = ballInfo[position[keys][0]][4] % 2;
const isSame = position[keys].every(
(num) => ballInfo[num][4] % 2 === firstNum
);
const arr = isSame ? [0, 2, 4, 6] : [1, 3, 5, 7];
for (const dir of arr) {
newInfo.push([+i, +j, mess, speed, dir]);
}
}
}
dfs(newInfo, turn + 1);
};
dfs(info, 0);
};
const input = require('fs')
.readFileSync(process.platform === 'linux' ? '/dev/stdin' : './input.txt')
.toString()
.trim()
.split('\n');
const [n, m, k] = input[0].split(' ').map((v) => +v);
const ballInfos = input.slice(1).map((v) => v.split(' ').map((v) => +v));
main(n, m, k, ballInfos);
'코딩 테스트 > 백준' 카테고리의 다른 글
16957 체스판 위의 공 (0) | 2025.01.23 |
---|---|
12908 텔레포트 3 (0) | 2025.01.22 |
16958 텔레포트 (자바스크립트) (1) | 2025.01.22 |
17090 미로 탈출하기 (자바스크립트) (0) | 2025.01.21 |
17406 배열 돌리기 4 (자바스크립트) (1) | 2025.01.20 |