본문 바로가기
PS

백준 10253번 C++ 헨리

by mtoc 2019. 5. 20.


헨리


이제 10 살이 된 헨리(Henry)는 수학에 소질이 있다. 수학선생님인 아메스(Ahmes)는 오늘 헨리에게 분수에 대해 가르쳐줬고, 헨리는 분수를 이리저리 계산해보는 것이 너무 재미있었다. 그러던 중에 헨리는 1 보다 작은 분수를 여러 개의 서로 다른 단위분수의 합으로 표현할 수 있다는 것을 알아내었다. 여기서 단위분수란 분자가 1 인 분수를 말한다. 헨리는 여러 개의 분수에 대해 이를 시도해봤고, 시도해본 분수들은 모두 서로 다른 단위분수의 합으로 표현할 수 있었다. 예를 들어, 423은 16+1138와 같이 두 개의 단위 분수의 합으로 나타낼 수 있다. 

헨리는 이런 발견을 선생님인 아메스에게 자랑스럽게 이야기했다. 아메스는 이를 듣고는 크게 기뻐하며 어린 제자를 칭찬했고, 이와 같이 하나의 분수를 서로 다른 단위분수의 합으로 표현한 것을 헨리식 표현법(Henry representation)이라고 이름 지었다. 즉, 분수 ab의 헨리식 표현법은 총합이 ab 와 같게 되는 서로 다른 단위분수의 나열이다. 헨리와 아메스는 헨리식 표현법에 대하여 더욱 연구하였고, 마침내 모든 1 보다 작은 분수는 헨리식 표현법이 가능함을 증명하였다. 또한 헨리식 표현법이 유일하지 않다는 것도 알 수 있었다. 예를 들면, 57=12+15+170=12+16+121=12+17+114 와 같이 여러 가지 다른 헨리식 표현법이 존재할 수 있다. 단, 정의에 의해, 헨리식 표현법에는 같은 단위분수가 두 개 이상 포함될 수 없으므로 23=13+13 는 헨리식 표현법이 아님을 유념해야 한다.

아메스와 헨리는 또한 주어진 분수의 헨리식 표현법을 구하는 간단한 방법도 고안해냈다. a<b 인 양의 정수 a와 b로 이루어진 분수 ab가 주어질 때에, 먼저 1x1ab를 만족하는 가장 큰 단위 분수 1x1를 계산한다. 그런 다음 ab 에서 1x1를 뺀 나머지에 대하여 위의 과정을 반복한다. 즉, 1x2ab1x1를 만족하는 가장 큰 단위분수 1x2를 계산하고 뺀다. 이러한 과정을 나머지가 남지 않을 때까지 반복한다. 그러면 서로 다른 단위분수들 1x1,1x2,1x3,을 순서대로 얻게 되며 그들의 합은 정확히 ab와 같아진다. 아메스와 헨리는 이 알고리즘이 항상 종료하며 합이 ab가 되는 서로 다른 단위분수들, 즉 헨리식 표현법을 출력함을 증명하였다.

아메스와 헨리는 당신에게 그들의 알고리즘을 컴퓨터 프로그램으로 구현해줄 것을 부탁했다. 입력으로 주어지는 1 보다 작은 분수 ab 를 아메스와 헨리의 알고리즘을 수행하여 헨리식 표현법을 계산할 때에 마지막 단위 분수의 분모를 출력하는 프로그램을 작성하시오. 예를 들어. ab=57라면, 아메스와 헨리의 알고리즘은 57=12+15+170 을 출력하게 되므로 당신의 프로그램은 반드시 70 을 출력해야 한다.





코드

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
//
// Created by az91t on 2019-05-20.
//
#include <iostream>
 
int main() {
    int T, a, b, denominator;
    std::cin>>T;
    while(T>0) {
        std::cin>>a>>b;
        denominator=2;
        while((a*denominator-b)!=0) {//약분이 문제
            if(b%a==0) {
                if(b/a>=denominator){
                    denominator=b/a;
                    break;
                }
            }
 
            if(a*denominator<b) {//a*denominator-b<0라 하면 오답나옴
                denominator++;
            }
 
            if (a*denominator>b) {
                a=a*denominator-b;
                b=b*denominator;
                denominator++;
            }
        }
        std::cout<<denominator<<"\n";
        T--;
    }
 
    return 0;
}
cs







그놈의 시간초과

문제 자체는 크게 어렵지 않다.

시간 초과가 문제일 뿐...

이거 한 두세시간 동안 풀다가 빡쳐서 저녁 먹고 좀 쉬다가 다시 시작

처음에는 굉장히 단순히 생각했다

분수를 만들려면 어떻게 해야하지, 분자, 분모는 어떻게 표현하지...

그래서 구조체까지 만들었는데 그렇게까지 하지 않아도 된다는 걸 깨달았다

그리고 굳이 함수를 만들지 않아도 된다는 걸 깨닫고 메인함수만 썼는데 그러다가 다시 재귀로...

하다가 결국 메인으로 돌아왔다


시간을 어떻게 줄이지? 이게 문제였다.

시간 초과는 웬만해서는 안 나는 것 같다. 그냥 틀렸다는 뜻이다.

무한 루프가 발생했다는 뜻이니까.

게시판을 참고하니, 최대공약수(gcd)를 이용하라는 말이 있었다.

그 말이 무슨 말인지 잘 몰랐는데 그냥 나머지가 0일 때 골라내주면 된다는 뜻이었다

그리고 9999/10000의 경우에서 자꾸 오답이 나와서, 다른 분들의 코드를 넣고 돌려봤다 ㅠㅠ

진짜 처음이었다. 하지만 풀고 싶었다...

그랬더니 비교연산에서 문제가 있는 것 같았다. 나와 로직이 비슷한 분의 코드를 보고 고쳤다.

나는 처음에 a*denominator-b<0로 비교했다.

그런데 a*denominator<b로 했을 때와 다른 결과값이 나오는 것이다.

숫자가 크면 클수록, 그 차이는 벌어진다.

아마 오버플로우 때문이라고 생각하는데, 난 오버플로우를 잘 모른다 ㅠㅠ 그래서 그 원인을 파악하는데 시간이 걸렸던 듯하다.




오늘 깨달은 것

난 지금까지 무턱대고 그냥 어려운 문제만 풀었다.

그러면 안 될 것 같다는 생각이, 리모컨 문제와 헨리를 풀면서 느꼈다.

틀리고, 내 문제점이 뭔지 알아도 원인과 해결할 방법을 찾지 못한다는 것이다.

이건 좀 더 공부가 필요한 부분인 것 같다.

내일부터는 자바스크립트 위주로, 정답률 높은 문제부터 차근차근 풀어나가야겠다.

조급해하지 말자.

며칠 전에는 어떤 문제는 차근차근 풀어나가자는 의미로 썼는데 오늘은 다르다.

너무 높은 곳에서부터 시작하려 하지 말자. 힘겨워서 금방 좌절하고 포기해버릴 수도 있겠다는 생각이 들었다.

내 실력을 인지하고 쉬운 것부터 시작해야겠다.

이제라도 반성했으니 다행이다. 내일도 화이팅

'PS' 카테고리의 다른 글

백준 2439번 C++ 어이없는 실수  (0) 2019.05.23
백준 1094번 C++ 막대기  (0) 2019.05.20
백준 1107번 C++ 리모컨 문제 (추가)  (0) 2019.05.18
백준 1157번 C++ 단어 공부  (2) 2019.05.13
백준 1181번 C++ 단어 정렬하기  (0) 2019.04.11

댓글