포스트

BOJ1193

BaekJoon 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번째 분수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 X(1 ≤ X ≤ 10,000,000)가 주어진다.

출력

첫째 줄에 분수를 출력한다.

나의 첫번째 답

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
#include <iostream>

using namespace std;

string whereIam(int num) {

    int curr = 1;
    int row = 1;
    int col = 1;

    while(num != curr) {

        if(row == 1) {      // 1행 
            if(col % 2 == 1) { col++; curr++; continue; } 
            else { row++; col--; curr++; continue; }
        } 
        else if(col == 1) {     // 1열
            if(row % 2 == 0) { row++; curr++; continue; }    
            else { row--; col++; curr++; continue;}
        }
        else{
            if((row + col) % 2 == 0) { row--; col++; curr++; continue; }
            else {row++; col--;  curr++; continue; }
        }
    }

    return to_string(row) + "/" + to_string(col);
}

int main() {

    int input;
    cin >> input;

    cout << whereIam(input) << endl;

    return 0;
}

우선 문제의 조건은 다음과 같은 순서로 분수에 숫자를 매겼었다. image

보다보니 분수들의 분자와 분모가 각각 행, 열과 같다는 생각이 들었고,

처음의 1행1열의 칸에서 시작해, 위 사진에서 화살표가 가리키는 순서대로 행렬 위를 지그재그로 순회하면 되겠다고 생각했다.

그래서 위와 같이 작성했다.

백준에서도 정답이라고 했지만, 적어도 문제에서 의도하는 바는 이것이 아니라고 생각해서 좀 더 나은 답을 찾았다.


배열을 다시 보면, (왼쪽 하단에서 오른쪽 상단으로 향하는) 한 대각선 상의 분수들은 모두 분자와 분모의 합이 같다.

대각선에 레벨이란 개념을 만들고, 분자와 분모의 합이 이것과 동일하게하자.

그러면 (입력받았던 숫자)를 이 레벨을 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
#include <iostream>

std::string findFraction(int x) {
    int level = 1; // 현재 대각선의 레벨 (분자와 분모의 합)
    while (x > level) {
        x -= level;
        level++;
    }

    int numerator, denominator;
    if (level % 2 == 1) {
        // 홀수 레벨: 왼쪽 아래로 이동. 분자가 크고 분모가 작아짐
        numerator = level - x + 1;
        denominator = x;
    } else {
        // 짝수 레벨: 오른쪽 위로 이동. 분자가 작아지고 분모가 커짐
        numerator = x;
        denominator = level - x + 1;
    }

    return std::to_string(numerator) + "/" + std::to_string(denominator);
}

int main() {
    int input;
    std::cin >> input;
    std::cout << findFraction(input) << std::endl;
    return 0;
}


image

기존의 답과 비교하면 약간의 메모리와 시간을 절약할 수 있었다.

코드의 가독성과 길이를 고려했을 때, 확실히 두번째 방법이 더 직관적이어서 나은 방법인 것 같다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.