basic-math

백준 기초 수학 문제 모음

[백준 문제풀이] 1011번 Fly me to the Alpha Centauri


1011번 Fly me to the Alpha Centauri (Gold 5)

느낀 점

어려운 문제도 계속 생각하면 풀린다.

문제

https://www.acmicpc.net/problem/1011

우현이는 어린 시절, 지구 외의 다른 행성에서도 인류들이 살아갈 수 있는 미래가 오리라 믿었다. 그리고 그가 지구라는 세상에 발을 내려 놓은 지 23년이 지난 지금, 세계 최연소 ASNA 우주 비행사가 되어 새로운 세계에 발을 내려 놓는 영광의 순간을 기다리고 있다.

그가 탑승하게 될 우주선은 Alpha Centauri라는 새로운 인류의 보금자리를 개척하기 위한 대규모 생활 유지 시스템을 탑재하고 있기 때문에, 그 크기와 질량이 엄청난 이유로 최신기술력을 총 동원하여 개발한 공간이동 장치를 탑재하였다. 하지만 이 공간이동 장치는 이동 거리를 급격하게 늘릴 경우 기계에 심각한 결함이 발생하는 단점이 있어서, 이전 작동시기에 k광년을 이동하였을 때는 k-1 , k 혹은 k+1 광년만을 다시 이동할 수 있다. 예를 들어, 이 장치를 처음 작동시킬 경우 -1 , 0 , 1 광년을 이론상 이동할 수 있으나 사실상 음수 혹은 0 거리만큼의 이동은 의미가 없으므로 1 광년을 이동할 수 있으며, 그 다음에는 0 , 1 , 2 광년을 이동할 수 있는 것이다. ( 여기서 다시 2광년을 이동한다면 다음 시기엔 1, 2, 3 광년을 이동할 수 있다. )

김우현은 공간이동 장치 작동시의 에너지 소모가 크다는 점을 잘 알고 있기 때문에 x지점에서 y지점을 향해 최소한의 작동 횟수로 이동하려 한다. 하지만 y지점에 도착해서도 공간 이동장치의 안전성을 위하여 y지점에 도착하기 바로 직전의 이동거리는 반드시 1광년으로 하려 한다.

김우현을 위해 x지점부터 정확히 y지점으로 이동하는데 필요한 공간 이동 장치 작동 횟수의 최솟값을 구하는 프로그램을 작성하라.

입력

입력의 첫 줄에는 테스트케이스의 개수 T가 주어진다. 각각의 테스트 케이스에 대해 현재 위치 x 와 목표 위치 y 가 정수로 주어지며, x는 항상 y보다 작은 값을 갖는다. (0 ≤ x < y < 231)

출력

각 테스트 케이스에 대해 x지점으로부터 y지점까지 정확히 도달하는데 필요한 최소한의 공간이동 장치 작동 횟수를 출력한다.

풀이

y의 최댓값이 2의 31승 –1로 컸기 때문에 수학적으로 접근해야하는 문제라고 생각했다. 고로 규칙성을 찾기 위해 노력했다.

처음에는 오직 1만 이동할 수 있고 마지막에도 오직 1을 이동해야 하기 때문에 이동 count의 최대 이동거리전체 이동 중 1회 이동거리가 가장 긴 수 간의 규칙성을 발견할 수 있었다.

결론적으로 이동 횟수가 홀수 2n-1회일 때는 최대 이동거리를 n^2이며, 짝수 2n회일 때는 n(n+1)라는 식을 유도할 수 있었다.

완전 탐색으로 접근할 경우 시간초과가 뜰 것 같아서, 위의 수식을 사용해서 이동거리가 포함될 최대 이동 횟수 중 홀수와 짝수일 경우를 조건문을 통해 풀이했다.

소스코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const fs = require("fs");
const input = fs.readFileSync("/dev/stdin").toString().trim().split("\n");

const T = parseInt(input[0]);
const answerArr = [];

for (let i = 1; i <= T; i++) {
  const c = input[i].split(" ").map((num) => parseInt(num));
  const distance = c[1] - c[0];
  const max = Math.ceil(Math.sqrt(distance));
  if (distance <= max * (max - 1)) {
    answerArr.push(max * 2 - 2);
  } else {
    answerArr.push(max * 2 - 1);
  }
}

console.log(answerArr.join("\n"));

[백준 문제풀이] 1002번 터렛


1002번 터렛 (Silver 4)

문제

https://www.acmicpc.net/problem/1002

조규현과 백승환은 터렛에 근무하는 직원이다. 하지만 워낙 존재감이 없어서 인구수는 차지하지 않는다. 다음은 조규현과 백승환의 사진이다.

이석원은 조규현과 백승환에게 상대편 마린(류재명)의 위치를 계산하라는 명령을 내렸다. 조규현과 백승환은 각각 자신의 터렛 위치에서 현재 적까지의 거리를 계산했다.

조규현의 좌표 (x1, y1)와 백승환의 좌표 (x2, y2)가 주어지고, 조규현이 계산한 류재명과의 거리 r1과 백승환이 계산한 류재명과의 거리 r2가 주어졌을 때, 류재명이 있을 수 있는 좌표의 수를 출력하는 프로그램을 작성하시오.

입력

첫째 줄에 테스트 케이스의 개수 T가 주어진다. 각 테스트 케이스는 다음과 같이 이루어져 있다.

한 줄에 x1, y1, r1, x2, y2, r2가 주어진다. x1, y1, x2, y2는 -10,000보다 크거나 같고, 10,000보다 작거나 같은 정수이고, r1, r2는 10,000보다 작거나 같은 자연수이다.

출력

각 테스트 케이스마다 류재명이 있을 수 있는 위치의 수를 출력한다. 만약 류재명이 있을 수 있는 위치의 개수가 무한대일 경우에는 –1을 출력한다.

풀이

각 터렛의 위치가 [같음, 다름] 각각의 경우에서 원이 [내접할 때, 외접할 때, 겹칠 때, 반지름이 같을 때]로 나눠서 쉽게 풀 수 있었다.

소스코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
const fs = require("fs");

const input = fs.readFileSync("/dev/stdin").toString().trim().split("\n");

const T = parseInt(input[0]);
const answerArr = [];

function checkCount(numArr) {
  const xFir = numArr[0];
  const yFir = numArr[1];
  const rFir = numArr[2];
  const xSec = numArr[3];
  const ySec = numArr[4];
  const rSec = numArr[5];
  const max = Math.max(rFir, rSec);
  const min = Math.min(rFir, rSec);

  const distance = Math.sqrt(
    Math.pow(xFir - xSec, 2) + Math.pow(yFir - ySec, 2)
  );
  if (xFir === xSec && yFir === ySec) {
    if (rFir === rSec) {
      answerArr.push(-1);
      return;
    } else {
      answerArr.push(0);
      return;
    }
  } else {
    if (distance === max) {
      answerArr.push(2);
      return;
    } else if (distance < max) {
      if (distance + min === max) {
        answerArr.push(1);
        return;
      } else if (distance + min < max) {
        answerArr.push(0);
        return;
      } else {
        answerArr.push(2);
        return;
      }
    } else {
      if (distance === max + min) {
        answerArr.push(1);
        return;
      } else if (distance > max + min) {
        answerArr.push(0);
        return;
      } else {
        answerArr.push(2);
        return;
      }
    }
  }
}

for (let i = 1; i <= T; i++) {
  const numbers = input[i].split(" ").map((num) => parseInt(num));
  checkCount(numbers);
}

console.log(answerArr.join("\n"));

[백준 문제풀이] 3053번 택시 기하학


3053번 택시 기하학 (Bronze 3)

문제

https://www.acmicpc.net/problem/3053

19세기 독일 수학자 헤르만 민코프스키는 비유클리드 기하학 중 택시 기하학을 고안했다.

택시 기하학에서 두 점 T1(x1,y1), T2(x2,y2) 사이의 거리는 다음과 같이 구할 수 있다.

D(T1,T2) = x1-x2 + y1-y2

두 점 사이의 거리를 제외한 나머지 정의는 유클리드 기하학에서의 정의와 같다.

따라서 택시 기하학에서 원의 정의는 유클리드 기하학에서 원의 정의와 같다.

원: 평면 상의 어떤 점에서 거리가 일정한 점들의 집합

반지름 R이 주어졌을 때, 유클리드 기하학에서 원의 넓이와, 택시 기하학에서 원의 넓이를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 반지름 R이 주어진다. R은 10,000보다 작거나 같은 자연수이다.

출력

첫째 줄에는 유클리드 기하학에서 반지름이 R인 원의 넓이를, 둘째 줄에는 택시 기하학에서 반지름이 R인 원의 넓이를 출력한다. 정답과의 오차는 0.0001까지 허용한다.

풀이

택시 기하학의 개념을 이해하는게 푸는 것보다 오래 걸렸다. 결국 내용을 이해해보면, 택시 기하학에서는 원의 넓이가 2*r^2 였다.


[백준 문제풀이] 4153번 직각삼각형


4153번 직각삼각형 (Bronze 3)

문제

https://www.acmicpc.net/problem/4153

과거 이집트인들은 각 변들의 길이가 3, 4, 5인 삼각형이 직각 삼각형인것을 알아냈다. 주어진 세변의 길이로 삼각형이 직각인지 아닌지 구분하시오.

입력

입력은 여러개의 테스트케이스로 주어지며 마지막줄에는 0 0 0이 입력된다. 각 테스트케이스는 모두 30,000보다 작은 양의 정수로 주어지며, 각 입력은 변의 길이를 의미한다.

출력

각 입력에 대해 직각 삼각형이 맞다면 “right”, 아니라면 “wrong”을 출력한다.

풀이

피타고라스의 정리를 이용해서 풀 수 있었다. 나는 최댓값을 구해 빗변으로 삼은 뒤 배열에서 제거해서 했는데, 다른 사람들의 풀이를 보니 정렬을 사용하면 더 효율적으로 할 수 있다는 걸 배웠다.

소스코드 (피타고라스의 정리)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
const fs = require("fs");

const input = fs.readFileSync("/dev/stdin").toString().trim().split("\n");
const answerArr = [];
let count = 0;

function isRight(triangle) {
  answerArr.push("wrong");
  const hypo = Math.max(...triangle);
  const index = triangle.indexOf(hypo);
  triangle.splice(index, 1);
  if (
    Math.pow(hypo, 2) ===
    Math.pow(triangle[0], 2) + Math.pow(triangle[1], 2)
  ) {
    answerArr[count] = "right";
  }
}

while (parseInt(input[count][0]) !== 0) {
  const tri = input[count].split(" ").map((num) => parseInt(num));
  isRight(tri);
  count++;
}

console.log(answerArr.join("\n"));

[백준 문제풀이] 9020번 골드바흐의 추측


9020번 골드바흐의 추측 (Silver 1)

문제

https://www.acmicpc.net/problem/9020

1보다 큰 자연수 중에서 1과 자기 자신을 제외한 약수가 없는 자연수를 소수라고 한다. 예를 들어, 5는 1과 5를 제외한 약수가 없기 때문에 소수이다. 하지만, 6은 6 = 2 × 3 이기 때문에 소수가 아니다.

골드바흐의 추측은 유명한 정수론의 미해결 문제로, 2보다 큰 모든 짝수는 두 소수의 합으로 나타낼 수 있다는 것이다. 이러한 수를 골드바흐 수라고 한다. 또, 짝수를 두 소수의 합으로 나타내는 표현을 그 수의 골드바흐 파티션이라고 한다. 예를 들면, 4 = 2 + 2, 6 = 3 + 3, 8 = 3 + 5, 10 = 5 + 5, 12 = 5 + 7, 14 = 3 + 11, 14 = 7 + 7이다. 10000보다 작거나 같은 모든 짝수 n에 대한 골드바흐 파티션은 존재한다.

2보다 큰 짝수 n이 주어졌을 때, n의 골드바흐 파티션을 출력하는 프로그램을 작성하시오. 만약 가능한 n의 골드바흐 파티션이 여러 가지인 경우에는 두 소수의 차이가 가장 작은 것을 출력한다.

입력

첫째 줄에 테스트 케이스의 개수 T가 주어진다. 각 테스트 케이스는 한 줄로 이루어져 있고 짝수 n이 주어진다.

출력

각 테스트 케이스에 대해서, n보다 크고, 2n보다 작거나 같은 소수의 개수를 출력한다.

풀이

각 테스트 케이스에 대해서 주어진 n의 골드바흐 파티션을 출력한다. 출력하는 소수는 작은 것부터 먼저 출력하며, 공백으로 구분한다.

소스코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
const fs = require("fs");

const input = fs.readFileSync("/dev/stdin").toString().trim().split("\n");
const T = parseInt(input[0]);
const answerArr = [];

for (let i = 1; i <= T; i++) {
  const number = parseInt(input[i]);
  let a = number / 2;
  let b = number - a;

  while (true) {
    let isPrime = true;
    if (a % 2 === 0 || b % 2 === 0) {
      if (!(a === 2 && b === 2)) {
        isPrime = false;
      }
    } else {
      for (let m = 3; m <= Math.sqrt(a); m += 2) {
        if (a % m === 0) {
          isPrime = false;
          break;
        }
      }
      if (isPrime) {
        for (let n = 3; n <= Math.sqrt(b); n += 2) {
          if (b % n === 0) {
            isPrime = false;
            break;
          }
        }
      }
    }
    if (isPrime) {
      answerArr.push(`${a} ${b}`);
      break;
    } else {
      a -= 1;
      b += 1;
    }
  }
}

console.log(answerArr.join("\n"));

사족 (2022.04.26)

이 당시에는 소수를 구하는 방식으로 풀었는데, 지금 돌아보면 에라토스테네스의 체로 접근하는 것이 더 나은 풀이 같다.


[백준 문제풀이] 3009번 네 번째 점


3009번 네 번째 점 (Bronze 3)

문제

https://www.acmicpc.net/problem/3009

세 점이 주어졌을 때, 축에 평행한 직사각형을 만들기 위해서 필요한 네 번째 점을 찾는 프로그램을 작성하시오.

입력

세 점의 좌표가 한 줄에 하나씩 주어진다. 좌표는 1보다 크거나 같고, 1000보다 작거나 같은 정수이다.

출력

직사각형의 네 번째 점의 좌표를 출력한다.

제한
1 ≤ w, h ≤ 1,000
1 ≤ x ≤ w-1
1 ≤ y ≤ h-1
x, y, w, h는 정수

풀이

직사각형을 만들기 위해 입력에 주어지는 x, y 값들이 결국 두 번씩 반복되어야 한다. x, y 각각 배열을 만들어서 풀었다.

소스코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
const fs = require("fs");

const input = fs.readFileSync("/dev/stdin").toString().trim().split("\n");

const a = input[0].split(" ");
const b = input[1].split(" ");
const c = input[2].split(" ");

const line = [a, b, c];

const xArr = [];
const yArr = [];

let x;
let y;

for (let i = 0; i <= 2; i++) {
  xArr.push(parseInt(line[i][0]));
  yArr.push(parseInt(line[i][1]));
}

for (let l = 0; l <= 2; l++) {
  const xDot = parseInt(line[l][0]);
  const yDot = parseInt(line[l][1]);
  if (xArr.indexOf(xDot) === xArr.lastIndexOf(xDot)) {
    x = xDot;
  }
  if (yArr.indexOf(yDot) === yArr.lastIndexOf(yDot)) {
    y = yDot;
  }
}

console.log(`${x} ${y}`);

[백준 문제풀이] 1085번 직사각형에서 탈출


1085번 직사각형에서 탈출 (Bronze 3)

문제

https://www.acmicpc.net/problem/1085

한수는 지금 (x, y)에 있다. 직사각형은 각 변이 좌표축에 평행하고, 왼쪽 아래 꼭짓점은 (0, 0), 오른쪽 위 꼭짓점은 (w, h)에 있다. 직사각형의 경계선까지 가는 거리의 최솟값을 구하는 프로그램을 작성하시오.

입력

첫째 줄에 x, y, w, h가 주어진다.

출력

첫째 줄에 문제의 정답을 출력한다.

제한
1 ≤ w, h ≤ 1,000
1 ≤ x ≤ w-1
1 ≤ y ≤ h-1
x, y, w, h는 정수

풀이

x, y, w, h, 0, 0 간의 차이 비교를 통해 간단히 풀 수 있었다.

소스코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
const fs = require("fs");

const input = fs.readFileSync("/dev/stdin").toString().trim().split(" ");

const x = parseInt(input[0]);
const y = parseInt(input[1]);
const w = parseInt(input[2]);
const h = parseInt(input[3]);

let min;

if (w - x < x) {
  min = w - x;
} else {
  min = x;
}

if (h - y < y) {
  if (h - y < min) {
    min = h - y;
  }
} else if (min > y) {
  min = y;
}

console.log(min);

[백준 문제풀이] 4948번 베르트랑 공준


4948번 베르트랑 공준 (Silver 2)

문제

https://www.acmicpc.net/problem/4948

베르트랑 공준은 임의의 자연수 n에 대하여, n보다 크고, 2n보다 작거나 같은 소수는 적어도 하나 존재한다는 내용을 담고 있다.

이 명제는 조제프 베르트랑이 1845년에 추측했고, 파프누티 체비쇼프가 1850년에 증명했다.

예를 들어, 10보다 크고, 20보다 작거나 같은 소수는 4개가 있다. (11, 13, 17, 19) 또, 14보다 크고, 28보다 작거나 같은 소수는 3개가 있다. (17,19, 23)

자연수 n이 주어졌을 때, n보다 크고, 2n보다 작거나 같은 소수의 개수를 구하는 프로그램을 작성하시오.

입력

입력은 여러 개의 테스트 케이스로 이루어져 있다. 각 케이스는 n을 포함하는 한 줄로 이루어져 있다.

입력의 마지막에는 0이 주어진다.

출력

각 테스트 케이스에 대해서, n보다 크고, 2n보다 작거나 같은 소수의 개수를 출력한다.

풀이

반복문과 제곱근 나누기 방식의 에라토노스체로 접근했다.

소스코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
const fs = require("fs");

const input = fs
  .readFileSync("/dev/stdin")
  .toString()
  .trim()
  .split("\n")
  .map((el) => el * 1);

const max = Math.max(...input);
let screen = Array.from({ length: max * 2 + 1 }, () => true);
screen[0] = false;
screen[1] = false;

for (let i = 2; i <= max * 2; i++) {
  if (screen[i]) {
    for (let j = 2; i * j <= max * 2; j++) {
      screen[i * j] = false;
    }
  }
}

let answer = Array.from({ length: input.length - 1 }, () => 0);
for (let i = 0; i < input.length - 1; i++) {
  for (let j = input[i] + 1; j <= input[i] * 2; j++) {
    if (screen[j]) answer[i] += 1;
  }
}

console.log(answer.join("\n"));

[백준 문제풀이] 1929번 소수 구하기


1929번 소수 구하기 (Silver 3)

문제

https://www.acmicpc.net/problem/1929

M이상 N이하의 소수를 모두 출력하는 프로그램을 작성하시오.

입력

첫째 줄에 자연수 M과 N이 빈 칸을 사이에 두고 주어진다. (1 ≤ M ≤ N ≤ 1,000,000) M이상 N이하의 소수가 하나 이상 있는 입력만 주어진다.

출력

한 줄에 하나씩, 증가하는 순서대로 소수를 출력한다.

시간 제한 : 2초, 메모리 제한 : 256mb

첫 번째 풀이

이번이야말로 에라토스테네스의 체를 사용해야하나 싶었는데, 1,000,000까지 배수의 배열을 만드는 것이 비효율적일 것 같았다. 해서 제곱근까지의 곱을 비교하는 로직을 사용했다.

수가 커서 이전에 사용했던 직접 나누어서 계산하는 로직을 사용하면, 시간 초과가 생길 것 같았다.

직접 나누는 로직의 시간 복잡도는 O(N)이고, 제곱근까지의 수를 나누어서 계산하는 것은 O(√ N)로, 앞의 방법보다 빠르다.

소스코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
const fs = require("fs");
const [M, N] = fs
  .readFileSync("/dev/stdin")
  .toString()
  .trim()
  .split(" ")
  .map((el) => el * 1);

let answer = "";
let screen = Array.from({ length: N + 1 }, () => true);
screen[0] = false;
screen[1] = false;

for (let i = 2; i <= Math.floor(Math.sqrt(N)); i++) {
  if (screen[i]) {
    for (let j = 2; i * j <= N; j++) {
      screen[i * j] = false;
    }
  }
}

for (let i = M; i <= N; i++) {
  if (screen[i]) answer += i + "\n";
}

console.log(answer);

[백준 문제풀이] 11653번 소인수분해


11653번 소인수분해 (Silver 5)

문제

https://www.acmicpc.net/problem/11653

정수 N이 주어졌을 때, 소인수분해하는 프로그램을 작성하시오.

입력

첫째 줄에 정수 N (1 ≤ N ≤ 10,000,000)이 주어진다.

출력

N의 소인수분해 결과를 한 줄에 하나씩 오름차순으로 출력한다. N이 1인 경우 아무것도 출력하지 않는다.

제한시간 : 1초

첫 번째 풀이

N이 10,000,000이하라서, 전부 일일이 나눠보는 것은 문제가 있다고 생각했다. 소인수분해라는 것은 결국 소수로 나눠지는 것이기 때문에, N까지의 소수를 먼저 구한 뒤 하나씩 나눠보는 방식이 맞다고 생각했다.

아니었다.

두 번째 풀이

작은 수부터 하나씩 나눠보면, 자연스럽게 소인수분해가 된다는 것을 알았다. 다만 나눠지지 않을때는 수를 하나씩 올리면서 실행해보았다.

소스코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const fs = require("fs");

let input = parseInt(fs.readFileSync("/dev/stdin").toString().trim());
const primes = [];

let divider = 2;
while (input >= divider) {
  if (input % divider === 0) {
    input = input / divider;
    primes.push(divider);
  } else {
    divider++;
  }
}

console.log(primes.join("\n"));

[백준 문제풀이] 2581번 소수


2581번 소수 (Silver 5)

문제

https://www.acmicpc.net/problem/2581

자연수 M과 N이 주어질 때 M이상 N이하의 자연수 중 소수인 것을 모두 골라 이들 소수의 합과 최솟값을 찾는 프로그램을 작성하시오.

예를 들어 M=60, N=100인 경우 60이상 100이하의 자연수 중 소수는 61, 67, 71, 73, 79, 83, 89, 97 총 8개가 있으므로, 이들 소수의 합은 620이고, 최솟값은 61이 된다.

출력

M이상 N이하의 자연수 중 소수인 것을 모두 찾아 첫째 줄에 그 합을, 둘째 줄에 그 중 최솟값을 출력한다.

단, M이상 N이하의 자연수 중 소수가 없을 경우는 첫째 줄에 -1을 출력한다.

제한시간 : 1초

풀이

M과 N이 10,000 이하의 자연수라서, 에라토스테네스의 체를 사용해야하나 생각이 들었다. 문제는 메모리가 128mb 라는 것이었다.

그냥 나누기로 했더니 풀렸다. 자꾸 오류가 났었는데, 배열을 Boolean 값으로 검증하는 방식보다 배열의 길이가 0인지 검증하는 쪽이 더 정확하다는 것을 알게되었다.

소스코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
const fs = require("fs");

const input = fs.readFileSync("/dev/stdin").toString().trim().split("\n");

const a = parseInt(input[0]);
const b = parseInt(input[1]);
const primeNumbers = [];
let sum = 0;

for (let i = a; i <= b; i++) {
  if (i === 2) {
    primeNumbers.push(i);
    sum += i;
  } else if (i !== 1) {
    let multiple = false;
    for (let l = 2; l < i; l++) {
      if (i % l === 0) {
        multiple = true;
      }
    }
    if (!multiple) {
      primeNumbers.push(i);
      sum += i;
    }
  }
}

if (!primeNumbers.length) {
  console.log(-1);
} else {
  const min = Math.min(...primeNumbers);
  console.log(sum);
  console.log(min);
}

[백준 문제풀이] 1978번 소수 찾기


1978번 소수 찾기 (Silver 4)

문제

https://www.acmicpc.net/problem/1978

주어진 수 N개 중에서 소수가 몇 개인지 찾아서 출력하는 프로그램을 작성하시오.

입력

첫 줄에 수의 개수 N이 주어진다. N은 100이하이다. 다음으로 N개의 수가 주어지는데, 수는 1000 이하의 자연수이다.

풀이 : 에라토스테네스의 체

소수를 구하는 공식이 있을 것 같아서 서치해보았고, 에라토스테네스의 체라는 것을 알게 되었다. 에라토스테네스의 체는 1이 아닌 수의 배수들을 제외한 값들을 소수로 판단하여 계산하는 것으로, 모든 수를 그 이하의 다른 수로 나누는 것보다 효율적이라고 한다.

소스코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
const fs = require("fs");

const input = fs.readFileSync("/dev/stdin").toString().trim().split("\n");

const N = parseInt(input[0]);
const numbers = input[1].trim().split(" ");
const nonMultiples = [];

numbers.map((number) => {
  let multiple = false;

  if (parseInt(number) === 1) {
    multiple = true;
  }

  for (let l = 2; l < parseInt(number); l++) {
    if (parseInt(number) % l === 0) {
      multiple = true;
    }
  }

  if (parseInt(number) === 2) {
    nonMultiples.push(number);
  } else if (!multiple) {
    nonMultiples.push(number);
  }
});

if (numbers === []) {
  console.log(0);
} else {
  console.log(nonMultiples.length);
}

[백준 문제풀이] 2839번 설탕 배달


2839번 설탕 배달 (Bronze 1)

문제

https://www.acmicpc.net/problem/2839

상근이는 요즘 설탕공장에서 설탕을 배달하고 있다. 상근이는 지금 사탕가게에 설탕을 정확하게 N킬로그램을 배달해야 한다. 설탕공장에서 만드는 설탕은 봉지에 담겨져 있다. 봉지는 3킬로그램 봉지와 5킬로그램 봉지가 있다.

상근이는 귀찮기 때문에, 최대한 적은 봉지를 들고 가려고 한다. 예를 들어, 18킬로그램 설탕을 배달해야 할 때, 3킬로그램 봉지 6개를 가져가도 되지만, 5킬로그램 3개와 3킬로그램 1개를 배달하면, 더 적은 개수의 봉지를 배달할 수 있다.

상근이가 설탕을 정확하게 N킬로그램 배달해야 할 때, 봉지 몇 개를 가져가면 되는지 그 수를 구하는 프로그램을 작성하시오.

첫째 줄에 N이 주어진다. (3 ≤ N ≤ 5000)

상근이가 배달하는 봉지의 최소 개수를 출력한다. 만약, 정확하게 N킬로그램을 만들 수 없다면 -1을 출력한다.

풀이

N이 5000까지이기 때문에 단순 반복 계산은 아닐거라고 생각했다.

! 아이디어
나머지와 몫을 사용하면 간단히 풀 수 있지 않을까? 5키로그램 봉지를 최대한 많이 가져가면 가져갈 봉지가 줄어든다.

3의 봉지와 5의 봉지를 반복문 없이 계산할 수 있지 않을까 했는데 어려웠다.

5로 나누어서 나머지가 0이 된다면 제일 적은 봉지 수이기 때문에 반복문에 첫 부분에 조건문으로 넣어주고, 총 무게에서 3을 계속 빼어서 count를 통해 3키로 봉지를 세어서 남은 무게를 5로 나눈 것과 더해주었다.

나중에 알고보니 이게 그리디 알고리즘이었다더라.


[백준 문제풀이] 2775번 부녀회장이 될테야


2775번 부녀회장이 될테야 (Bronze 1)

문제

https://www.acmicpc.net/problem/2775

평소 반상회에 참석하는 것을 좋아하는 주희는 이번 기회에 부녀회장이 되고 싶어 각 층의 사람들을 불러 모아 반상회를 주최하려고 한다.

이 아파트에 거주를 하려면 조건이 있는데, “a층의 b호에 살려면 자신의 아래(a-1)층의 1호부터 b호까지 사람들의 수의 합만큼 사람들을 데려와 살아야 한다” 는 계약 조항을 꼭 지키고 들어와야 한다.

아파트에 비어있는 집은 없고 모든 거주민들이 이 계약 조건을 지키고 왔다고 가정했을 때, 주어지는 양의 정수 k와 n에 대해 k층에 n호에는 몇 명이 살고 있는지 출력하라. 단, 아파트에는 0층부터 있고 각층에는 1호부터 있으며, 0층의 i호에는 i명이 산다.

제한 시간 : 1초

제한 : 1 ≤ k, n ≤ 14

첫 번째 풀이

제한과 시간을 봤을 때, 각 층이 올라갈때마다 바로 아래층과 이전 방의 값을 더해서 배열로 만들어주는 것으로 구현이 가능할 수 있겠다고 생각했다.

틀림.

두 번째 풀이

자꾸 에러가 나서 2일 동안 고민했는데, 알고보니까 사례 수는 층, 호수를 전부 포함하는 것이라서 반복문을 T번 더 해주어야했다. 어썸 코딩… (2021.11.12.)

풀이 이후 자꾸 에러가 나서 서치를 해봤는데, 이 문제의 아래에 전부 1로된 층을 추가한 뒤, 파스칼의 삼각형으로 접근, 이항정리 문제로 푸는 방법을 찾았다. 오늘도 어썸 코딩.

소스코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const fs = require("fs");

const input = fs.readFileSync("/dev/stdin").toString().trim().split("\n");

const T = parseInt(input[0]);

for (let i = 1; i < T * 2; i = i + 2) {
  const k = parseInt(input[i]);
  const n = parseInt(input[i + 1]);
  const apartment = [];

  for (let l = 0; l <= k; l++) {
    apartment.push([1]);
    for (let j = 1; j < n; j++) {
      if (l === 0) {
        apartment[l].push(j + 1);
      } else {
        apartment[l].push(apartment[l - 1][j] + apartment[l][j - 1]);
      }
    }
  }
  console.log(apartment[k][n - 1]);
}

[백준 문제풀이] 10757번 큰 수 A + B


10757번 큰 수 A + B (Bronze 5)

배운 것

문제는 간단했는데, js에서 처리할 수 있는 수에 한계가 있어서 BigInt라는 자료형이 있다는 것을 알게 되었다. BigInt는 끝에 n이 붙기 때문에 string으로 변환해서 출력해주어야한다.

문제

https://www.acmicpc.net/problem/10757

두 정수 A와 B를 입력받은 다음, A+B를 출력하는 프로그램을 작성하시오.


[백준 문제풀이] 2869번 달팽이는 올라가고 싶다


2869번 달팽이는 올라가고 싶다 (Bronze 1)

문제

https://www.acmicpc.net/problem/2869

땅 위에 달팽이가 있다. 이 달팽이는 높이가 V미터인 나무 막대를 올라갈 것이다.

달팽이는 낮에 A미터 올라갈 수 있다. 하지만, 밤에 잠을 자는 동안 B미터 미끄러진다. 또, 정상에 올라간 후에는 미끄러지지 않는다.

달팽이가 나무 막대를 모두 올라가려면, 며칠이 걸리는지 구하는 프로그램을 작성하시오.

첫째 줄에 세 정수 A, B, V가 공백으로 구분되어서 주어진다. (1 ≤ B < A ≤ V ≤ 1,000,000,000)

제한시간 : 0.15초

첫 번째 풀이

수가 크기 때문에 반복문을 사용하는 것은 불가능하고, 나눠서 해결하는 방식이라고 생각했다. 다음 날 낮에 올라가는 것까지 계산해야하기 때문에, 미리 낮에 올라가는걸 뺀 후 그 수를 넘는 때를 구하기로 했다.

25%에서 틀림.

두 번째 풀이

25%에서 틀렸다는 것은 예외처리가 잘 되지 못한 것 같다.

floor를 사용해서 문제를 풀었었는데, v – a의 값이 a보다 작으면 반내림을 사용하게 되면 오답이 나오게 되기 때문에 반올림을 사용해서 문제를 풀어야했다.


[백준 문제풀이] 10250번 ACM 호텔


10250번 ACM 호텔 (Bronze 3)

문제

https://www.acmicpc.net/problem/10250

ACM 호텔 매니저 지우는 손님이 도착하는 대로 빈 방을 배정하고 있다. 고객 설문조사에 따르면 손님들은 호텔 정문으로부터 걸어서 가장 짧은 거리에 있는 방을 선호한다고 한다. 여러분은 지우를 도와 줄 프로그램을 작성하고자 한다. 즉 설문조사 결과 대로 호텔 정문으로부터 걷는 거리가 가장 짧도록 방을 배정하는 프로그램을 작성하고자 한다.

문제를 단순화하기 위해서 호텔은 직사각형 모양이라고 가정하자. 각 층에 W 개의 방이 있는 H 층 건물이라고 가정하자 (1 ≤ H, W ≤ 99). 그리고 엘리베이터는 가장 왼쪽에 있다고 가정하자(그림 1 참고). 이런 형태의 호텔을 H × W 형태 호텔이라고 부른다. 호텔 정문은 일층 엘리베이터 바로 앞에 있는데, 정문에서 엘리베이터까지의 거리는 무시한다. 또 모든 인접한 두 방 사이의 거리는 같은 거리(거리 1)라고 가정하고 호텔의 정면 쪽에만 방이 있다고 가정한다.

방 번호는 YXX 나 YYXX 형태인데 여기서 Y 나 YY 는 층 수를 나타내고 XX 는 엘리베이터에서부터 세었을 때의 번호를 나타낸다. 즉, 그림 1 에서 빗금으로 표시한 방은 305 호가 된다.

손님은 엘리베이터를 타고 이동하는 거리는 신경 쓰지 않는다. 다만 걷는 거리가 같을 때에는 아래층의 방을 더 선호한다. 예를 들면 102 호 방보다는 301 호 방을 더 선호하는데, 102 호는 거리 2 만큼 걸어야 하지만 301 호는 거리 1 만큼만 걸으면 되기 때문이다. 같은 이유로 102 호보다 2101 호를 더 선호한다.

여러분이 작성할 프로그램은 초기에 모든 방이 비어있다고 가정하에 이 정책에 따라 N 번째로 도착한 손님에게 배정될 방 번호를 계산하는 프로그램이다. 첫 번째 손님은 101 호, 두 번째 손님은 201 호 등과 같이 배정한다. 그림 1 의 경우를 예로 들면, H = 6이므로 10 번째 손님은 402 호에 배정해야 한다.

첫 번째 풀이

문제는 복잡해보이나, 결국 H를 N으로 나눈 몫 + 1이 호수가 되고, 나머지가 층 수가 된다. 각각을 구한뒤 문자열로 만들어 더 해준다.

소스코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
const fs = require("fs");
const input = fs.readFileSync("/dev/stdin").toString().trim().split("\n");

const c = parseInt(input[0]);

for (let i = 1; i <= c; i++) {
  const line = input[i].split(" ");
  const h = parseInt(line[0]);
  const w = parseInt(line[1]);
  const n = parseInt(line[2]);
  const room = Math.ceil(n / h);
  let floor;
  let answer;

  if (n % h === 0) {
    floor = h;
  } else {
    floor = n % h;
  }

  if (room >= 10) {
    console.log(`${floor}${room}`);
  } else {
    console.log(`${floor}0${room}`);
  }
}

[백준 문제풀이] 1193번 분수찾기


1193번 분수찾기 (Bronze 1)

문제

https://www.acmicpc.net/problem/1193

무한히 큰 배열에 다음과 같이 분수들이 적혀있다.

1/1 1/2 1/3 1/4 1/5 …
2/1 2/2 2/3 2/4 … …
3/1 3/2 3/3 … … …
4/1 4/2 … … … …
5/1 … … … … …
… … … … … …
이와 같이 나열된 분수들을 1/1 → 1/2 → 2/1 → 3/1 → 2/2 → … 과 같은 지그재그 순서로 차례대로 1번, 2번, 3번, 4번, 5번, … 분수라고 하자.

X가 주어졌을 때, X번째 분수를 구하는 프로그램을 작성하시오.

첫 번째 풀이

수학 능력이 머리에 없는건지 도저히 모르겠어서 구글링을 해보았다.

수학적인 사고는 자연어로 이루어진 문제를 분석, 해결 가능한 수준으로 나누고 패턴을 찾아내는 과정이라는 말을 읽고 참 인상 깊게 새겼다. 결국 수학은 복잡한 문제를 단순화하고 패턴을 찾아내서 일반화하는 것이라는 걸 읽고 수학에 대한 새로운 생각을 할 수 있었다.

결국 주기성을 찾아내는 것이라고.

패턴화 하려고 노력했고, 답을 참고하지 않고 풀어낼 수 있었다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
const fs = require("fs");

const input = fs.readFileSync("/dev/stdin").toString().trim();

const num = parseInt(input);
let range = 1;
let line = 1;
let answer = 0;
let fraction = 0;

if (num === 1) {
  answer = `1/1`;
} else {
  while (range < num) {
    line++;
    range += line;
  }

  if (line % 2 === 1) {
    fraction = range - num + 1;
  } else {
    fraction = line - (range - num);
  }

  answer = `${fraction}/${line - fraction + 1}`;
}

console.log(answer);

[백준 문제풀이] 1712번 손익분기점


1712번 손익분기점 (Bronze 4)

문제

https://www.acmicpc.net/problem/1712

월드전자는 노트북을 제조하고 판매하는 회사이다. 노트북 판매 대수에 상관없이 매년 임대료, 재산세, 보험료, 급여 등 A만원의 고정 비용이 들며, 한 대의 노트북을 생산하는 데에는 재료비와 인건비 등 총 B만원의 가변 비용이 든다고 한다.

예를 들어 A=1,000, B=70이라고 하자. 이 경우 노트북을 한 대 생산하는 데는 총 1,070만원이 들며, 열 대 생산하는 데는 총 1,700만원이 든다.

노트북 가격이 C만원으로 책정되었다고 한다. 일반적으로 생산 대수를 늘려 가다 보면 어느 순간 총 수입(판매비용)이 총 비용(=고정비용+가변비용)보다 많아지게 된다. 최초로 총 수입이 총 비용보다 많아져 이익이 발생하는 지점을 손익분기점(BREAK-EVEN POINT)이라고 한다.

A, B, C가 주어졌을 때, 손익분기점을 구하는 프로그램을 작성하시오.

첫 번째 풀이

A : 고정 비용, B : 생산당 가변 비용, C : 매출

손익분기점을 구하라.

1
2
3
4
5
6
7
8
9
10
11
const answer = 0;
let 매출 = -A;

if (B > C) {
	console.log(-1);
} else {
	while (매출 > 0) {
		매출 += (C  B);
		answer++
	};
};

이와 같이 접근했다. => 시간초과

두 번째 풀이

이 문제가 ‘수학 능력’ 카테고리에 있었다는 것을 간과했었다.

반복문을 써서 풀면 당연히 늦어질 수 밖에 없고, 개당 수익으로 고정 손해 나눠준 뒤 반올림 해준 뒤 +1 해주면 되는 일이었다.

풀이 소스코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const fs = require("fs");

const input = fs.readFileSync("/dev/stdin").toString().trim().split(" ");

const a = parseInt(input[0]);
const b = parseInt(input[1]);
const c = parseInt(input[2]);

if (b >= c) {
  answer = -1;
} else {
  answer = Math.floor(a / (c - b)) + 1;
}

console.log(answer);

[백준 문제풀이] 2292번 벌집


2292번 벌집 (Bronze 2)

느낀 점

Keep It Super Simple

문제

https://www.acmicpc.net/problem/2292

위의 그림과 같이 육각형으로 이루어진 벌집이 있다. 그림에서 보는 바와 같이 중앙의 방 1부터 시작해서 이웃하는 방에 돌아가면서 1씩 증가하는 번호를 주소로 매길 수 있다. 숫자 N이 주어졌을 때, 벌집의 중앙 1에서 N번 방까지 최소 개수의 방을 지나서 갈 때 몇 개의 방을 지나가는지(시작과 끝을 포함하여)를 계산하는 프로그램을 작성하시오. 예를 들면, 13까지는 3개, 58까지는 5개를 지난다.

풀이

수열로 풀이 하려고 했는데, 너무 수학적으로 접근했었다는 것을 깨달았다. 그냥 간단하게 한 줄이 늘어날때마다 한 칸이 늘어나게 된다.

1까지는 1번, 7까지는 2번, 19까지는 3번, 37까지는 4번 이와 같이 이동하게 된다. 이걸 수열로 1, 7, 19와 같은 수를 수열로 생각해서 문제에 접근하였다. 입력된 숫자가 포함되는 범위까지의 수를 찾을 때까지 거리를 하나 씩 추가해주었다.

소스코드

1
2
3
4
5
6
7
8
9
10
11
12
13
const fs = require("fs");

const number = parseInt(fs.readFileSync("/dev/stdin").toString());

let distance = 1;
let range = 1;

while (number > range) {
  range += distance * 6;
  distance++;
}

console.log(distance);

Check out other tags: