문제
무한히 큰 배열에 다음과 같이 분수들이 적혀있다.
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번째 분수를 구하는 프로그램을 작성하시오.
풀이
분수들의 순서에서 규칙성을 찾자!
<순서>
1. 분자/분모 가 나오는 규칙성을 찾는다.
2. 입력 받은 x가 표의 정확히 어느 위치인지 알아야한다.
3. 분자/분모 를 만들자.
줄 번호 별로 나오는 분수를 나열해보면 규칙이 눈에 쉽게 보인다.
줄 번호가 짝수
일 경우,
분자 : (줄 번호)~1 까지 -1 씩 줄어듬
분모 : 1~(줄 번호) 까지 +1 씩 늘어남
줄 번호가 홀수
일 경우,
짝수일 경우와 반대임을 알 수 있다.
찾은 규칙성을 토대로 우리는 x번째의 분수를 구하려면 x가 몇 번째 줄 번호
인지 알 필요가 있다.
줄 번호
에 속한 분수의 개수는 줄 번호
(개) 만큼 존재한다.
즉, 반복문(while)으로 1(sum)에 다가 +(i) : 1, 2, 3, 4, 5 ... 씩 늘려가면서 더해 각 줄의 첫 번째 숫자를 나타내는 총합(sum)보다 x가 작다면 반복문을 멈춰 줄 번호(i)를 알아낼 수 있다.
int x, sum=1, i=0; //sum은 1 초기화, i는 0 초기화
~~
while(1){
if(sum>x) break;
i++;
sum+=i;
} //i는 줄번호
위와 같은 과정으로 우리는 x의 줄 번호(i)를 알아냈다.
이제 마지막으로 분자와 분모를 만들어 출력해주면 끝난다.
1번에서 우리는 분자/분모 의 규칙을 찾았다. x번째에 맞는 분수를 만들려면 x번째가 줄 번호
내에서도 몇 번째 수인지 알아야한다. 왜냐하면, (줄번호)~1 까지 1씩 줄어듬. 이라는 규칙에 적용시키려면 (줄번호)-? 몇을 빼줘야 맞는 분자/분모 가 나오는지 알 수 있기 때문이다.
ex) 13은 5번 줄의 3번째이다.
x - 줄 번호의 초항(첫 번째 수)
: 줄 번호에서의 x의 위치
ex) 13 - 11 = 2 (초항은 0번째이다, 분자/분모가 (줄번호)-0 이니까!)
sum-i
: 줄 번호의 초항
따라서, x-(sum-i)
: 줄 번호에서의 x의 위치
sum-i
가 초항인 이유 : 위에서 줄 번호를 구하기 위해 돌린 반복문에서 sum은 x의 값보다 한 줄 앞의 초항으로 만들어진다. 따라서, i(줄 번호)를 빼준 값이 i의 초항과 같아진다.
int num, den; //분자, 분모
~~
if(i%2==0){ //짝수라면
num=1+(x-(sum-i)); //(sum-i) : 줄번호의 초항(첫번째 수)
den=i-(x-(sum-i)); //x-(sum-i) : 초항으로부터 x가 얼마나 떨어져있는지 (줄번호)의 몇번째 수 인가!
}
else{ //홀수라면
num=i-(x-(sum-i));
den=1+(x-(sum-i));
}
풀이 코드
#include<iostream>
using namespace std;
int main(void)
{
cin.tie(NULL); ios_base::sync_with_stdio(false);
int num, den; //분자, 분모
int x,sum=1,i=0;
cin>>x;
while(1){
if(sum>x) break;
i++;
sum+=i;
} //i는 줄번호
if(i%2==0){ //짝수라면
num=1+(x-(sum-i)); //(sum-i) : 줄번호의 초항(첫번째 수)
den=i-(x-(sum-i)); //x-(sum-i) : 초항으로부터 x가 얼마나 떨어져있는지 (줄번호)의 몇번째 수 인가!
}
else{ //홀수라면
num=i-(x-(sum-i));
den=1+(x-(sum-i));
}
cout<<num<<"/"<<den;
}
잡담
'기본 수학' 카테고리에 있는 문제들은 문제의 '규칙성'을 찾는 게 핵심 포인트인 문제가 많은 것 같다.