[CS50] Chapter 2. C언어


1) C언어 기초

2) 문자열

3) 조건문과 루프

4) 자료형, 형식 지정자, 연산자

5) 사용자 정의 함수, 중첩 루프

6) 하드웨어의 한계


[백준 문제풀이] 8979번 올림픽


8979번 올림픽 (Silver 3)

문제

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

올림픽은 참가에 의의가 있기에 공식적으로는 국가간 순위를 정하지 않는다. 그러나, 많은 사람들이 자신의 국가가 얼마나 잘 하는지에 관심이 많기 때문에 비공식적으로는 국가간 순위를 정하고 있다. 두 나라가 각각 얻은 금, 은, 동메달 수가 주어지면, 보통 다음 규칙을 따라 어느 나라가 더 잘했는지 결정한다.

금메달 수가 더 많은 나라 금메달 수가 같으면, 은메달 수가 더 많은 나라 금, 은메달 수가 모두 같으면, 동메달 수가 더 많은 나라 각 국가는 1부터 N 사이의 정수로 표현된다. 한 국가의 등수는 (자신보다 더 잘한 나라 수) + 1로 정의된다. 만약 두 나라가 금, 은, 동메달 수가 모두 같다면 두 나라의 등수는 같다. 예를 들어, 1번 국가가 금메달 1개, 은메달 1개를 얻었고, 2번 국가와 3번 국가가 모두 은메달 1개를 얻었으며, 4번 국가는 메달을 얻지 못하였다면, 1번 국가가 1등, 2번 국가와 3번 국가가 공동 2등, 4번 국가가 4등이 된다. 이 경우 3등은 없다.

각 국가의 금, 은, 동메달 정보를 입력받아서, 어느 국가가 몇 등을 했는지 알려주는 프로그램을 작성하시오.

입력

입력의 첫 줄은 국가의 수 N(1 ≤ N ≤ 1,000)과 등수를 알고 싶은 국가 K(1 ≤ K ≤ N)가 빈칸을 사이에 두고 주어진다. 각 국가는 1부터 N 사이의 정수로 표현된다. 이후 N개의 각 줄에는 차례대로 각 국가를 나타내는 정수와 이 국가가 얻은 금, 은, 동메달의 수가 빈칸을 사이에 두고 주어진다. 전체 메달 수의 총합은 1,000,000 이하이다.

출력

출력은 단 한 줄이며, 입력받은 국가 K의 등수를 하나의 정수로 출력한다. 등수는 반드시 문제에서 정의된 방식을 따라야 한다.

소스코드

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
65
66
// 입력 값 처리 부분
const fs = require("fs");
const [numbers, ...medals] = fs
  .readFileSync("/dev/stdin")
  .toString()
  .split("\n")
  .map((line) => line.split(" ").map((el) => el * 1));
const [N, K] = numbers;

solveProblem();

// 문제 해결 방식
// 1. 주어진 K 값으로 탐색하여 target을 구한다.
// 2. target과 타국들과의 메달 비교를 통해 rank를 도출.
function solveProblem() {
  const target = getTarget(K, medals);
  const rank = getRank(target, medals);

  console.log(rank);
}

// target 국가를 구하는 함수
// 주어진 K를 전체 국가의 ID과 비교하여 찾는다.
// @return {Array}: target 국가 정보
function getTarget(K, medals) {
  let result;
  for (let i = 0; i < N; i++) {
    if (medals[i][0] === K) result = medals[i];
  }

  return result;
}

// rank를 구하는 함수
// 금메달 비교 후 target 국가보다 많으면 rank + 1
// 금메달이 같으면, 은메달 비교 후 target 국가보다 많으면 rank + 1
// 은메달이 같으면, 동메달 비교 후 target 국가보다 많으면 rank + 1
// @return {number}: 최종 rank를 반환
function getRank(target, medals) {
  let result = 1;

  // 전체 국가와 비교
  for (let i = 0; i < N; i++) {
    // 본인 국가는 지나가기
    if (medals[i][0] === target[0]) continue;

    if (medals[i][1] >= target[1]) {
      // 금메달 비교
      if (medals[i][1] > target[1]) {
        result++;
      } else if (medals[i][2] >= target[2]) {
        // 은메달 비교
        if (medals[i][2] > target[2]) {
          result++;
        } else if (medals[i][3] >= target[3]) {
          // 동메달 비교
          if (medals[i][3] > target[3]) {
            result++;
          }
        }
      }
    }
  }

  return result;
}

[백준 문제풀이] 1063번 킹


1063번 킹 (Silver 3)

문제

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

8*8크기의 체스판에 왕이 하나 있다. 킹의 현재 위치가 주어진다. 체스판에서 말의 위치는 다음과 같이 주어진다. 알파벳 하나와 숫자 하나로 이루어져 있는데, 알파벳은 열을 상징하고, 숫자는 행을 상징한다. 열은 가장 왼쪽 열이 A이고, 가장 오른쪽 열이 H까지 이고, 행은 가장 아래가 1이고 가장 위가 8이다. 예를 들어, 왼쪽 아래 코너는 A1이고, 그 오른쪽 칸은 B1이다.

킹은 다음과 같이 움직일 수 있다.

R : 한 칸 오른쪽으로 L : 한 칸 왼쪽으로 B : 한 칸 아래로 T : 한 칸 위로 RT : 오른쪽 위 대각선으로 LT : 왼쪽 위 대각선으로 RB : 오른쪽 아래 대각선으로 LB : 왼쪽 아래 대각선으로 체스판에는 돌이 하나 있는데, 돌과 같은 곳으로 이동할 때는, 돌을 킹이 움직인 방향과 같은 방향으로 한 칸 이동시킨다. 아래 그림을 참고하자.

입력으로 킹이 어떻게 움직여야 하는지 주어진다. 입력으로 주어진 대로 움직여서 킹이나 돌이 체스판 밖으로 나갈 경우에는 그 이동은 건너 뛰고 다음 이동을 한다.

킹과 돌의 마지막 위치를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 킹의 위치, 돌의 위치, 움직이는 횟수 N이 주어진다. 둘째 줄부터 N개의 줄에는 킹이 어떻게 움직여야 하는지 주어진다. N은 50보다 작거나 같은 자연수이고, 움직이는 정보는 위에 쓰여 있는 8가지 중 하나이다.

출력

첫째 줄에 킹의 마지막 위치, 둘째 줄에 돌의 마지막 위치를 출력한다.

소스코드

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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
const fs = require("fs");
let [chessPieces, ...commands] = fs
  .readFileSync("/dev/stdin")
  .toString()
  .trim()
  .split("\n");

chessPieces = chessPieces.split(" ");
const N = chessPieces.pop();

solveProblem();

function solveProblem() {
  // 이동을 숫자의 증감으로 표현할 수 있도록
  // 열을 숫자로 변환함.
  chessPieces = positionToAscii(chessPieces);

  // 명령 배열을 돌며 명령 수행
  commands.forEach((command) => {
    chessPieces = handleCommand(chessPieces, command);
  });

  // 출력을 위해 다시 체스 포지션 문자열로 변경
  chessPieces = asciiToPosition(chessPieces);

  // 결과 출력
  console.log(chessPieces.join("\n"));
}

// 명령 수행
// @chessPieces {Array}: king, stone의 위치 정보를 담은 이차원 배열
// @command {String}: 명령 문자열
// @return {Array}: king, stone의 위치 정보를 담고 있는 이차원 배열
function handleCommand(chessPieces, command) {
  let [king, stone] = chessPieces;

  // king 이동.
  king = moveChessPiece(king, command);
  if (king[0] === stone[0] && king[1] === stone[1]) {
    // king과 store의 위치가 같으면,
    // stone도 이동시킴.
    stone = moveChessPiece(stone, command);
  }

  // 두 말의 위치가 보드 내에 있다면,
  // 변경된 위치 정보 반환
  if (checkPosition(...king) && checkPosition(...stone)) return [king, stone];

  // 두 말의 위치가 보드 밖에 있다면,
  // 변경전 위치 정보 반환
  return chessPieces;
}

// 체스말 이동 함수
// @chessPiece {Array} : 이동할 체스말 위치 정보
// @command {String}: 명령 문자열
function moveChessPiece(chessPiece, command) {
  let [movedColumn, movedRow] = chessPiece;

  switch (command[0]) {
    case "R":
      movedColumn++;
      break;
    case "L":
      movedColumn--;
      break;
    case "T":
      movedRow++;
      break;
    case "B":
      movedRow--;
      break;
  }

  if (command[1]) {
    switch (command[1]) {
      case "T":
        movedRow++;
        break;
      case "B":
        movedRow--;
        break;
    }
  }

  return [movedColumn, movedRow];
}

// 위치 확인 함수
// 체스말의 위치가 보드 내에 있는지 확인
// @column, row {String}: 체스말 열, 행 정보
// @return {Boolean}
function checkPosition(column, row) {
  if (column >= 65 && column <= 72 && row >= 1 && row <= 8) return true;

  return false;
}

// 체스판 위치 => 아스키코드 변환 함수
// @return {Array} : 아스키코드로 변환된 king, stone의 위치 정보 이차원 배열
function positionToAscii(chessPieces) {
  chessPieces = chessPieces.map((chessPiece) => {
    chessPiece = chessPiece.split("");
    chessPiece[0] = chessPiece[0].charCodeAt();
    chessPiece[1] = chessPiece[1] * 1;

    return chessPiece;
  });

  return chessPieces;
}

// 아스키코드 => 체스판 위치 변환 함수
// @return {Array} : 문자열로 변환된 king, stone의 위치 정보 배열
function asciiToPosition(chessPieces) {
  chessPieces = chessPieces.map((chessPiece) => {
    chessPiece[0] = String.fromCharCode(chessPiece[0]);
    chessPiece[1] = chessPiece[1] * 1;

    return chessPiece.join("");
  });

  return chessPieces;
}

[CS50] Chapter 1. 컴퓨팅 사고


1) 2진법

2) 정보의 표현

3) 알고리즘

4) Scratch

5) Scratch 심화


[백준 문제풀이] 10798번 세로읽기


10798번 세로읽기 (Bronze 1)

문제

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

아직 글을 모르는 영석이가 벽에 걸린 칠판에 자석이 붙어있는 글자들을 붙이는 장난감을 가지고 놀고 있다.

이 장난감에 있는 글자들은 영어 대문자 ‘A’부터 ‘Z’, 영어 소문자 ‘a’부터 ‘z’, 숫자 ‘0’부터 ‘9’이다. 영석이는 칠판에 글자들을 수평으로 일렬로 붙여서 단어를 만든다. 다시 그 아래쪽에 글자들을 붙여서 또 다른 단어를 만든다. 이런 식으로 다섯 개의 단어를 만든다. 아래 그림 1은 영석이가 칠판에 붙여 만든 단어들의 예이다.

A A B C D D a f z z 0 9 1 2 1 a 8 E W g 6 P 5 h 3 k x

한 줄의 단어는 글자들을 빈칸 없이 연속으로 나열해서 최대 15개의 글자들로 이루어진다. 또한 만들어진 다섯 개의 단어들의 글자 개수는 서로 다를 수 있다.

심심해진 영석이는 칠판에 만들어진 다섯 개의 단어를 세로로 읽으려 한다. 세로로 읽을 때, 각 단어의 첫 번째 글자들을 위에서 아래로 세로로 읽는다. 다음에 두 번째 글자들을 세로로 읽는다. 이런 식으로 왼쪽에서 오른쪽으로 한 자리씩 이동 하면서 동일한 자리의 글자들을 세로로 읽어 나간다. 위의 그림 1의 다섯 번째 자리를 보면 두 번째 줄의 다섯 번째 자리의 글자는 없다. 이런 경우처럼 세로로 읽을 때 해당 자리의 글자가 없으면, 읽지 않고 그 다음 글자를 계속 읽는다. 그림 1의 다섯 번째 자리를 세로로 읽으면 D1gk로 읽는다.

그림 1에서 영석이가 세로로 읽은 순서대로 글자들을 공백 없이 출력하면 다음과 같다:

Aa0aPAf985Bz1EhCz2W3D1gkD6x

칠판에 붙여진 단어들이 주어질 때, 영석이가 세로로 읽은 순서대로 글자들을 출력하는 프로그램을 작성하시오.

입력

총 다섯줄의 입력이 주어진다. 각 줄에는 최소 1개, 최대 15개의 글자들이 빈칸 없이 연속으로 주어진다. 주어지는 글자는 영어 대문자 ‘A’부터 ‘Z’, 영어 소문자 ‘a’부터 ‘z’, 숫자 ‘0’부터 ‘9’ 중 하나이다. 각 줄의 시작과 마지막에 빈칸은 없다.

출력

영석이가 세로로 읽은 순서대로 글자들을 출력한다. 이때, 글자들을 공백 없이 연속해서 출력한다.

소스코드

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

let answer = "";

for (let j = 0; j < 15; j++) {
  for (let i = 0; i < words.length; i++) {
    if (words[i][j]) answer += words[i][j];
  }
}

console.log(answer);