프로그래밍 공부
작성일
2024. 2. 27. 16:29
작성자
WDmil
728x90

문제 설명

시침, 분침, 초침이 있는 아날로그시계가 있습니다. 시계의 시침은 12시간마다, 분침은 60분마다, 초침은 60초마다 시계를 한 바퀴 돕니다. 따라서 시침, 분침, 초침이 움직이는 속도는 일정하며 각각 다릅니다. 이 시계에는 초침이 시침/분침과 겹칠 때마다 알람이 울리는 기능이 있습니다. 당신은 특정 시간 동안 알람이 울린 횟수를 알고 싶습니다.

 

다음은 0 5 30초부터 0 7 0초까지 알람이 울린 횟수를 세는 예시입니다.

 

 

가장 짧은 바늘이 시침, 중간 길이인 바늘이 분침, 가장 긴 바늘이 초침입니다.

알람이 울리는 횟수를 세기 시작한 시각은 0 5 30초입니다.

이후 0 6 0초까지 초침과 시침/분침이 겹치는 일은 없습니다.

 

0 6 0.501초에 초침과 시침이 겹칩니다. 이때 알람이 한 번 울립니다.

이후 0 6 6초까지 초침과 시침/분침이 겹치는 일은 없습니다.

 

0 6 6.102초에 초침과 분침이 겹칩니다. 이때 알람이 한 번 울립니다.

이후 0 7 0초까지 초침과 시침/분침이 겹치는 일은 없습니다.

0 5 30초부터 0 7 0초까지는 알람이 두 번 울립니다. 이후 약 0 7 0.584초에 초침과 시침이 겹쳐서 울리는 세 번째 알람은 횟수에 포함되지 않습니다.

 

다음은 12 0 0초부터 12 0 30초까지 알람이 울린 횟수를 세는 예시입니다.

 

 

알람이 울리는 횟수를 세기 시작한 시각은 12 0 0초입니다.

초침과 시침, 분침이 겹칩니다. 이때 알람이 한 번 울립니다. 이와 같이 0시 정각, 12시 정각에 초침과 시침, 분침이 모두 겹칠 때는 알람이 한 번만 울립니다.

 

이후 12 0 30초까지 초침과 시침/분침이 겹치는 일은 없습니다.

12 0 0초부터 12 0 30초까지는 알람이 한 번 울립니다.

 

알람이 울리는 횟수를 센 시간을 나타내는 정수 h1, m1, s1, h2, m2, s2가 매개변수로 주어집니다. 이때, 알람이 울리는 횟수를 return 하도록 solution 함수를 완성해주세요.

 

제한사항

  1. 0 ≤ h1, h2 ≤ 23
  2. 0 ≤ m1, m2 ≤ 59
  3. 0 ≤ s1, s2 ≤ 59
  4. h1시 m1분 s1초부터 h2시 m2분 s2초까지 알람이 울리는 횟수를 센다는 의미입니다.
  5. h1시 m1분 s1초 < h2시 m2분 s2초
  6. 시간이 23시 59분 59초를 초과해서 0시 0분 0초로 돌아가는 경우는 주어지지 않습니다.

입출력 예

 

h1 m1 s1 h2 m2 s2 Result
0 5 30 0 7 0 2
12 0 0 12 0 30 1
0 6 1 0 6 6 0
11 59 30 12 0 0 1
11 58 59 11 59 0 1
1 5 5 1 5 6 2
0 0 0 23 59 59 2852

문제 해설

일단, 생각하는 방법에 따라서 문제의 푸는 방식이 완전 달라진다.

 

아날로그를 디지털로 동작시키려고 한다면, 현재 이동전 이동 후의 초 시간에 따라 그 과정상 중간에 지정된 시침과 분침이 겹치는지, 해당 시침과 분침에 초침이 겹쳤었는지를 계산해야한다.

 

형식상, 데이터의 조건을 분할해서, 조건을 계산하고 조건별로 추가연산을 진행하게 할 수도 있다.

0시부터 24시까지의 시간중에서, 초침과 분침 시침이 만나는 횟수는 몃번인가를 생각해보자.

 

그리고, 해당 시간과정에서 예외처리 해야하는 과정이 무엇무엇인지 계산해보면 된다.


첫 번째 시도

#include <string>
#include <vector>

using namespace std;

float chackTomax(const float& i)
{
    return i >= 360 ? i - 360 : i;
}

bool sideIn(const float& f1, const float& f2, const float& C1, const float& C2)
{
    float chackf1 = chackTomax(f1);
    float chackf2 = chackTomax(f2);
    float chackC1 = chackTomax(C1);
    float chackC2 = chackTomax(C2);

    if ((max(chackf1, chackC1) < min(chackf2, chackC2)) ||
        max(f1, C1) < min(f2, C2))
        return true;
    return false;
}

int solution(int h1, int m1, int s1, int h2, int m2, int s2) {
    int answer = 0;

    float sPBack = (s1 * 6);
    float mPBack = (m1 * 6 + s1 * 0.1);
    float hPBack = ((h1 % 12) * 30 + (m1 * 0.5) + (s1 * (0.5 / 60)));

    bool mchack = false;
    bool hchack = false;

    while (h1 != h2 || m1 != m2 || s1 != s2)
    {
        s1++;

        float h1P((h1 % 12) * 30 + (m1 * 0.5) + (s1 * (0.5 / 60)));
        float m1P(m1 * 6 + s1 * 0.1);
        float s1P(s1 * 6);

        bool chackh = sideIn(sPBack, s1P, hPBack, h1P);
        bool chackm = sideIn(sPBack, s1P, mPBack, m1P);
        bool chackhm = sideIn(mPBack, m1P, hPBack, h1P);

        if (chackhm && !mchack && !hchack) {
                mchack = hchack = true;
                answer++;
        }
        else {
            if (chackm && !mchack) {
                mchack = true;
                answer++;
            }
            if (chackh && !hchack) {
                hchack = true;
                answer++;
            }
        }

        if (s1 == 60) {
            s1 = 0;
            m1++;
            mchack = hchack = false;
        }
        if (m1 == 60) {
            m1 = 0;
            h1++;
        }
        if (h1 == 24) {
            h1 = 0;
        }

        sPBack = s1P;
        mPBack = m1P;
        hPBack = h1P;
    }
    return answer;
}

실패

 

0초부터 계산해서, 시침과 분침이 겹치는지 초를 기준으로 1초 2초...이런식으로 전부다 계산해서 연산하였다.

 

중간에 시침과 분침, 초침이 겹치는 경우의 수 중 분침과 시침이 겹쳐있을 때 초침과 만나는 경우를 정상적으로 연산할 수 없었다.

 

아니, 시침과 분침의 크기를 알려주지 않고 겹침과 겹치지 않음을 분간하는건 어떻게 기준을 잡아야 하는가...


두 번째 시도

using namespace std;

void chackToPI(float& i)
{
    if (i >= 360) {
        while (i >= 360)
            i -= 360;
    }
    return;
}

int counttime(float h, float m, float s) {
    int result = -1;
    float hs = h * 30 + m * 0.5 + s * 0.5 / 60;
    chackToPI(hs);
    float ms = m * 6 + s * 0.1;
    chackToPI(ms);
    float ss = s * 6;
    chackToPI(ss);

    if (ss >= ms) result += 1;
    if (ss >= hs) result += 1;

    result += (h * 60 + m) * 2;
    result -= h;
    if (h >= 12) result -= 2;
    return result;
}

int solution(int h1, int m1, int s1, int h2, int m2, int s2) {
    int answer;
    if ((h1 == 0 || h1 == 12) && m1 == 0 && s1 == 0) answer = 1;
    else answer = 0;

    int time1 = counttime(h1, m1, s1);
    int time2 = counttime(h2, m2, s2);
    
    answer += time2 - time1;
    return answer;
}

성공

 

아예 연산기준을 바꾸어보았다.

그낭 0시0분0초부터 h1m1s1까지, 0시0분0초부터 h2m2s2까지 의 연산결과를 빼버렸다.

 

counttime에 데이터의 연산기준을 정렬하고, 현재 최종 h, m, s의 각도를 계산한다음에, 초침이 넘었는지 안넘었는지 확인하고 해당 연산 결과를 중첩한다.

 

그리고, 겹친 연산을, 시간과 분의 곱하기 2배.(시침과 분침이 겹쳤을 때) 임으로 더하고,

한시간에 한번 분침과 시침이 겹침으로, 시침만큼을 빼준다.

h가 12보다 클 경우, 정각을 지나게 됨으로, 2를 빼주면된다.

(12시를 넘길 경우, 시계가 한바퀴 돌게됨으로 000의 연산을 한번 더 해주어야 하기 때문, 시침분침 겹친걸 빼주는것,59분에서 00분으로 넘어가는 과정에서 초침과 분침 시침이 만나지 않게됨으로 2를 빼줌)

 

그리고, 0시 정각 부터 시작 또는 12시 정각 부터 시작은 항상 시작부터 시침과 분침 초침이 만남으로 answer는 1이된다.

728x90

'코딩테스트 문제 풀이' 카테고리의 다른 글

바탕화면 정리  (0) 2024.03.04
당구 연습  (0) 2024.02.29
[PCCP 기출문제] 2번 / 석유 시추  (0) 2024.02.26
[PCCE 기출문제] 10번 / 데이터 분석  (0) 2024.02.26
[PCCE 기출문제] 9번 / 이웃한 칸  (0) 2024.02.26