백준-단계별로 풀어보기/2-조건문

백준 2884 - 알람 시계

코딩크리처 2024. 7. 30. 13:54

문제 이름 : 알람 시계


문제

상근이는 알람을 듣고 일어나려고 하지만, 더 자려는 마음에 매일 학교를 지각한다.

상근이 친구 창영이는 "45분 일찍 알람 설정하기" 라는 자신의 방법을 소개했고, 상근이는 이를 도입하려 한다.

현재 상근이가 설정한 알람 시각이 주어졌을 때, 이를 언제로 고쳐야 하는지 구하는 프로그램을 작성하시오.

입력

첫째 줄에 두 정수 HM 이 주어진다. ( 0 <= H <= 23, 0 <= M <= 59 )

입력 시간은 24시간 표현을 사용한다.

24시간 표현에서 하루의 시작은 0:0 (자정) 이고, 끝은 23:59 (다음날 자정 1 분 전)이다.

시간을 나타낼 때, 불필요한 0은 사용하지 않는다.

출력

첫째 줄에 상근이가 창영이의 방법을 사용 할 때, 설정해야 하는 알람 시간을 출력한다.

(입력과 같은 형태로 출력하면 된다.)

예제 입력 1

10 10

예제 출력 1

9 25

예제 입력 2

0 30

예제 출력 2

23 45

예제 입력 3

23 40

예제 출력 3

22 55

먼저 문제에서 요구하는 것을 요약 해 보자.

이 문제에서 주어진 구현사항은, 바로 45분 일찍 설정하기 이다.

시계에서 45분을 일찍 설정한다는 의미는,

주어진 분(minute) 에서 -45 한다는 것이다.


하지만, 시간은 단순히 의 숫자만으로 표현되지 않는다.

의 변화에 따라, 시(Hour) 도 변한다.

이를 수학적인 시각에서 바라본다면, 에 속한다.

에 영향을 미치지 않지만, 에 영향을 미친다.

기본적으로 이러한 시각을 가지고 구현을 하면 편리해진다.


그 다음으로, 출력의 형식을 본다면,

시간은 0 ~ 23 으로 표현되며, 분은 0 ~ 59 으로 표현된다.

즉, 각각의 숫자 변수는 한계가 존재한다 이다.


그리고 더 고려 해 보아야 할 것은, 어떻게 의 계산 중

-45 를 구현 할 것인가? 이다.

위에서 말한 것과 동시에, 고려해야 할 두 가지가 존재한다.

  1. 이라는 요소에 영향을 받는다.
  2. 숫자의 계산 결과가 영역을 벗어 날 시, +1 or -1 계산을 한다.

위의 두 가지 고려사항을 가지고, 기능을 구현하면 된다.


Answer 1 - 중첩 비교문

import java.util.*;
import java.io.*;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        StringTokenizer st = new StringTokenizer(br.readLine());

        int H = Integer.parseInt(st.nextToken()); // 시
        int M = Integer.parseInt(st.nextToken()); // 분 

        if(M - 45 >= 0) { // 분 이 가질 수 있는 숫자 영역을 벗어나지 않았을 경우 
            M -= 45;
        } else { // 분 이 가질 수 있는 숫자 영역을 벗어났을 경우 --> 시간에 변화 
            M = 60 + (M - 45);

            if(H - 1 < 0) // 시간이 이미 0 시 였다면, -1시가 될 수 없으므로, 23시로 돌아온다.
                H = 23;
            else  // 아니라면 그냥 시간을 하나 빼면 된다.
                H--;
        }

        System.out.println(H + " " + M);
    }
}

위 계산 중 M = 60 + (M - 45) 의 의미에 대해서 모를 수 있는 사람을 위해 먼저 알려주고 시작한다.

M(분) 이 이미 45분보다 크다면, 45분 일찍 돌려놓는다고 해서 0~59 영역을 벗어나지 않는다.

따라서, 시간도 변화하지 않고 그저 M-45 해 주면 끝나는 일이다.

하지만, M-45 계산 결과 영역을 벗어나게 된다면, 말은 달라진다.

시계의 분은 마이너스가 될 수 없다. 그저 가질 수 있는 최고 수 에서 다시 내려 갈 뿐이다.

따라서, 이를 계산하기 위한 식이 M = 60 + (M - 45) 이다.

(M - 45) 는 0분, 혹은 60분에서부터 얼마나 더 반시계로 돌려야하는지를 음수 로 알려준다.

위 식의 결과는 마이너스이므로, 이를 그대로 60 과 더해주면 된다.


다시 돌아와서, 이 문제에는 총 2 개의 비교 사항이 존재한다.

먼저 분(M) 의 계산 결과가 영역을 벗어났는가?

그리고 나서 시간(H) 의 계산 결과가 영역을 벗어났는가?

이 두가지가 존재한다.

시간의 비교 사항 여부는 의 조건에 따라 달려있으므로, 종속되었다고 볼 수 있다.

만약 의 계산 결과가 수의 영역을 벗어났다면, 시간 의 계산 결과가 수의 영역을 벗어났는지를 비교한다.

비교 타임라인이 2 개인 결과, 중첩된 비교문 코드가 형성 된 것을 볼 수 있다.


Answer 2 - 흐름 비교문

import java.io.*;
import java.util.*;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        StringTokenizer st = new StringTokenizer(br.readLine());

        int H = Integer.parseInt(st.nextToken());
        int M = Integer.parseInt(st.nextToken());


        M = (M - 45 >= 0) ? M - 45 : 60 + (M - 45);

        H = (M + 45 < 60) ? H : (H - 1 >= 0) ? H - 1 : 23;
        /*
        if (M < 0) {
              if (H - 1 >= 0)
                    H--;
              else
                    H = 23; 
        } 
        */

        System.out.println(H + " " + M);
    }
}

사실, 위의 코드를 흐름 비교문이라고 작성했지만,

삼중문 을 이용하여 가독성에 있어 강제로 중첩을 피한 것과 다르지 않다.

위의 주석에 도대체 삼중문 안에 삼중문이 어떠한 형식으로 이루어 진 것인지 펼쳐놓았다.


그렇다면 삼중문 은 어떻게 사용할까?

값을 받을 변수 = (참 or 거짓이 되는 조건문) ? ("참" 일 시 실행되고 결과를 반환) : ("거짓" 일 시 실행되고 결과를 반환)

M = (M - 45 >= 0) ? M - 45 : 60 + (M - 45);

맨 앞에 혹은 거짓 이 되는 조건문에 의해, ? 뒤에서 : 로 구분되는 문장이 실행 및 반환되는 것이다.

가장 중요한 것은, 결국 if 문을 굉장히 간략화 한 버전이라는 것이다.

할당되어 반환 되는 함수라는 것을 잊으면 안된다.


삼중문 은 결국 일종의 함수 라는 것을 위에서 바로 언급했다.

이러한 특징 및 성질을 이용하여 H = (M + 45 < 60) ? H : (H - 1 >= 0) ? H - 1 : 23; 이 완성 된 것이다.

조건문과 실행식이 모두 모여 3개라서 삼중문 이 아니던가? 어떻게 그 이상의 표현을 가졌을까?

삼중문 내의 변수와도 같은 반환문도 결국은 일종의 함수 라는 것을 잊지 말라.


지금부터 중첩 삼중문에 대한 해체를 시작하겠다.

흐름을 이해하기 위해서, 왼쪽부터 오른쪽으로 읽는다는 것을 잊지 말았으면 한다.

더 쉬운 이해를 위해, 더 풀어서 설명하겠다.

A = (B) ? (C) : (D - 1)
==
값을 할당 받을 변수 혹은 주소 = (B) ? (B가 true 일때, C를 바로 반환하는 함수) : (B 가 false 일 때, D - 1 계산 후 결과값을 반환하는 함수)

삼중문을 처음 본다면, 위의 설명을 그냥 기억하면 좋다.

즉, 단순히 true or false 결과에 따라 값을 할당한다. 라고 이해하는 것이 아니라,

true or false 결과에 따라, 전자 혹은 후자의 함수 가 실행된다 라고 이해하면 된다.

이러한 과정을 이해한다면, 중첩 삼중문 에 대한 이해가 가능하다.


H = (M + 45 < 60) ? H : (H - 1 >= 0) ? H - 1 : 23;

위의 문장에 대해 해석을 시작 해 보겠다.

처음으로, (M + 45 < 60) 이 "참" 이라면, 곧바로 H 를 반환하며 끝이 난다.

그렇지 않고 "거짓" 이라면, (H - 1 >= 0) ? H - 1 : 23; 이라는 함수를 다시 반환하여,

여기서 값을 받으라고 하는 것이다.

그렇다면, 다시 해석을 시작 해 보자.

(H - 1 >= 0) 이 "참" 이라면, H - 1 이라는 결과를 반환한다.

"거짓"이라면, 23 을 반환하며 완전히 종료가 된다.