728x90
문제
https://www.acmicpc.net/problem/17143
풀이
이번 문제는 단순 구현 문제이지만 까다로운 로직이 필요한 구현 문제이다.
상어를 낚는 로직은 2차원 배열에서 해당 열에 가장 위에 있는 상어만 추출해주면된다.
const casting = (curPos) => {
for (let i = 0; i < r; i++) {
if (arr[i][curPos] !== 0) {
const target = arr[i][curPos][2];
arr[i][curPos] = 0;
return target;
}
}
return 0;
};
모든 상어들이 움직이는 로직을 담당하는 함수를 만든다.
이 함수에서 새로운 배치를 갖는 배열을 저장하도록 새로운 배열을 만든다.
이렇게 만들어진 배열에 각 상어의 새로운 위치를 담아준다.
담을때 같은 위치에 상어가 중복되어 있을 때 무게가 가장 큰 상어만 남겨두도록 설계한다.
const move = () => {
const temp = Array.from({ length: r }, () => Array(c).fill(0));
for (let i = 0; i < r; i++){
for (let j = 0; j < c; j++){
if (arr[i][j] !== 0) {
const [nY, nX, nD] = getNextPos(i, j, arr[i][j][0], arr[i][j][1]);
if (temp[nY][nX]) {
temp[nY][nX] = temp[nY][nX][2] < arr[i][j][2] ? [arr[i][j][0], nD, arr[i][j][2]] : temp[nY][nX];
}
else {
temp[nY][nX] = [arr[i][j][0], nD, arr[i][j][2]];
}
}
}
}
arr = temp;
}
이제 상어가 이동하는 함수를 만들자.
나는 이 로직이 가장 어려웠다....
예시를 들며 로직을 살펴보자.
길이가 4인 구간을 상어는 이동하면 반환점을 찍고 원래 자리쪽으로 돌아온다.
0123401234 방식이 아니라 012343210...이다.
싸이클의 길이만큼 나머진 연산을 해주면 0부터 시작하는 싸이클 시작점 부터의 거리를 구할 수 있다.
위에서 보면 알 수 있듯이 0부터 시작해서 4를 찍고 1까지 돌아오는 것이 위치 변화의 싸이클 범위이다.
수식으로 살펴보면 2 * C(or R) - 2이다.
그 다음 상어가 이동했을 때 최종 위치를 구해야 하는데, 이 로직이 상당히 어려웠다.......
상어의 초기 위치가 3이고 up 방향으로 5만큼 증가할때 4를 찍고 최종 위치인 0이 되어야 한다.
012343210 순서로 봤을 때 3부터 0까지 가야하며, 최종 위치를 도출하는 수식은 2 * R(or C) - 2 - 가야할 칸수 이다.
const getNextPos = (y, x, speed, direction) => {
if (direction === 1 || direction === 2) {
const cycle = (2 * r) - 2;
if (direction === 1) {
speed += 2 * (r - 1) - y;
}
else {
speed += y
}
speed %= cycle;
// cycle로 나눈 나머지가 r 보다 큰 경우는 cycle로 다시 0으로 돌아오지는 않지만, r에서 턴은 한 상태이다.
if (speed >= r) {
return [cycle - speed, x, 1];
}
else {
return [speed, x, 2];
}
}
else {
const cycle = (2 * c) - 2;
if (direction === 4) {
speed += 2 * (c - 1) - x;
}
else {
speed += x;
}
speed %= cycle;
if (speed >= c) {
return [y, cycle - speed, 4];
}
else {
return [y, speed, 3];
}
}
}
코드
const input = require('fs')
.readFileSync(process.platform === 'linux' ? '/dev/stdin' : __dirname + '/example.txt')
.toString().trim().split('\n').map(e => e.split(' ').map(Number));
const [r, c, m] = input.shift();
const sharks = input;
let arr = Array.from({ length: r }, () => Array(c).fill(0));
let answer = 0;
sharks.forEach(([r, c, s, d, z]) => {
arr[r - 1][c - 1] = [s, d, z];
})
const casting = (curPos) => {
for (let i = 0; i < r; i++) {
if (arr[i][curPos] !== 0) {
const target = arr[i][curPos][2];
arr[i][curPos] = 0;
return target;
}
}
return 0;
};
const getNextPos = (y, x, speed, direction) => {
if (direction === 1 || direction === 2) {
const cycle = (2 * r) - 2;
if (direction === 1) {
speed += 2 * (r - 1) - y;
}
else {
speed += y
}
speed %= cycle;
// cycle로 나눈 나머지가 r 보다 큰 경우는 cycle로 다시 0으로 돌아오지는 않지만, r에서 턴은 한 상태이다.
if (speed >= r) {
return [cycle - speed, x, 1];
}
else {
return [speed, x, 2];
}
}
else {
const cycle = (2 * c) - 2;
if (direction === 4) {
speed += 2 * (c - 1) - x;
}
else {
speed += x;
}
speed %= cycle;
if (speed >= c) {
return [y, cycle - speed, 4];
}
else {
return [y, speed, 3];
}
}
}
const move = () => {
const temp = Array.from({ length: r }, () => Array(c).fill(0));
for (let i = 0; i < r; i++){
for (let j = 0; j < c; j++){
if (arr[i][j] !== 0) {
const [nY, nX, nD] = getNextPos(i, j, arr[i][j][0], arr[i][j][1]);
if (temp[nY][nX]) {
temp[nY][nX] = temp[nY][nX][2] < arr[i][j][2] ? [arr[i][j][0], nD, arr[i][j][2]] : temp[nY][nX];
}
else {
temp[nY][nX] = [arr[i][j][0], nD, arr[i][j][2]];
}
}
}
}
arr = temp;
}
for (let i = 0; i < c; i++){
answer += casting(i);
move();
}
console.log(answer);
728x90
'코딩 테스트 > 백준' 카테고리의 다른 글
[Node.js] 17822_원판돌리기 (0) | 2024.06.27 |
---|---|
[Node.js] 17837_새로운 게임 2 (0) | 2024.06.26 |
[Node.js] 17779_게리맨더링 2 (0) | 2024.06.10 |
[Node.js] 17142_연구소3 (0) | 2024.06.05 |
[Node.js] 17140_이차원 배열과 연산 (0) | 2024.05.23 |