본문 바로가기

백준

[Node.js] 백준 - 기본 수학 문제 1 : 손익분기점, 벌집O(1), 분수찾기O(1)

📝 Node.js를 이용해 백준 문제 풀기



Node.js를 이용해서 백준 문제를 풀고 있습니다.


기본 수학 문제 1 (3개)

  • 최대한 반복문 없이 수학을 활용하도록 노력했습니다.

(1) 셀프 넘버


// (1) 손익분기점
const fs = require("fs");
const filePath = process.platform === "linux" ? "/dev/stdin" : "./input.txt";
let input = fs.readFileSync(filePath).toString().trim().split("\n");
input = input[0].split(" ").map((num) => Number(num));
const dCost = input[0];
const vCost = input[1];
const income = input[2];
let q = 0;

if (vCost >= income) {
  q = -1;
} else {
  q = Number.isInteger(dCost / (income - vCost))
    ? dCost / (income - vCost) + 1
    : Math.ceil(dCost / (income - vCost));
}

console.log(q);



(2) 벌집 : O(1)


// (2) 벌집
const fs = require("fs");
const filePath = process.platform === "linux" ? "/dev/stdin" : "./input.txt";
let input = fs.readFileSync(filePath).toString().trim().split("\n");
const target = Number(input[0]);
console.log(Math.ceil((3 + Math.sqrt(12 * target - 3)) / 6));

벌집의 경우 중심 부로 부터 깊이를 생각하여 1, 2, 3 ... 으로 벌집 방의 늘어 나는 개수에 규칙이 존재 합니다.

깊이 1 2 3 4 5 ...
개수 1 6 + 6*0 6 + 6*1 6 + 6*2 6+ 6*3 ...

깊이 별 방의 개수가 일정하게 규칙성을 가지고 늘어남을 확인하였습니다. 깊이를 d 로 생각하여 d 에 해당 하는 끝 값을 식으로 나타낼 수 있습니다.

1

1 + 6(1 + 10)

1 + 6(1 + 1
0) + 6(1 + 11)

...

1 + 6(1 + 1
0) + 6(1 + 1*1) + ... + 6(1 + n)

1 다음 부터는 등차 수열의 합을 이용한 공식을 활용하여 나타낼 수 있습니다.

1 + 2 + 3 + ... (n-1) + n -> n(n+1)/2

1 + Σ6(d-2)+6

1 + Σ6(d-1)

1 + 3d(d-1)

3d^2 -3d + 1

해당 식이 가르키는 값에 target이 들어올 때, target에 따른 Depth 깊이를 해로 구할 수 있습니다.

예를 들어, depth가 3인 경우는 끝 값은 19입니다. 그러면 target이 18인 경우 depth는 3보다 조금 작은 숫자 입니다.
depth가 2 인경우 끝값은 7 이므로 target이 7< t <=19 이면, depth는 2< d <=3 입니다.


target에 대한 depth가 소수점의 숫자 올림처리를 하면 해당 depth가 나오게 됩니다.


그래서 d를 구하는 근의 공식을 통해 식을 산출합니다.

3d^2 -3d + 1 = t

d = (3 + Math.sqrt(12 * t - 3)) / 6) 이며 이를 ceil를 통해 올림 처리 합니다.




(3) 분수 찾기: O(1)


위 벌집 문제와 비슷한 방식으로 풀어 낼 수 있습니다. 중요점은 가르키는 input이 몇 번째 줄인지, 그 줄의 몇 번째에 있는지 알아야 합니다.


// (3) 분수 찾기
const fs = require("fs");
const filePath = process.platform === "linux" ? "/dev/stdin" : "./input.txt";
let input = fs.readFileSync(filePath).toString().trim().split("\n");
const target = Number(input[0]);
// 등차수열의 합에 대한 근 찾기
const sol = (-1 + Math.sqrt(8 * target + 1)) / 2;
// 근을 통한 줄 찾기
const rowNum = Math.ceil(sol);
// 줄을 통해서 몇 번째인지 찾기
const colNum = target - (rowNum * (rowNum - 1)) / 2;

// 짝수 번째는 분모가 크고, 홀수 번째 줄은 분자가 크고
if (rowNum % 2 === 0) {
  console.log(`${colNum}/${rowNum - colNum + 1}`);
} else {
  console.log(`${rowNum - colNum + 1}/${colNum}`);
}