[백준] 1193: 분수 찾기 - 파이썬[python]

다인·2024년 8월 17일

백준

목록 보기
36/112

바로 규칙이 안 보여서 다른 날로 넘겼는데, 오래 걸릴 줄 알았는데 웬걸 규칙이 바로 보여서 코드가 술술 쳐졌다.(물론 정답 맞춰야 하니까 좀 생각하긴 했지ㅎ) 시간도 적게 걸려서 오 이게 맞는 방법?! 했는데 구글링해보니 아이디어는 정답이더랑ㅎㅅㅎ 뿌듯 😋
그래도 내 코드를 더 간단히 정리가 가능해서 내가 푼 코드와 정리한 코드의 풀이를 한 번 적어보겠당

규칙 찾기

  • 처음에는 가로, 세로로도 규칙을 찾아보려고 했는데 응용까지 이어지지 못했고, 대각선을 본 순간 코드가 쭉 짜졌다.
  • 보라색으로 묶은 애들끼리 보면 분모와 분자의 합이 모두 동일하다. 그리고 묶인 애들이 n번째 묶음이라고 하면 (1부터 시작) 합은 n+1이 된다. 이 합은 왼쪽 핑크색으로 적힌 값이다.
    자 그럼 여기서 더 나아가서 해당 자리의 수를 찾으려면 어떻게 해야 할까? 파란색 화살표를 보면 분모나 분자가 1씩 줄어들거나 늘어남을 알 수 있다. 그러면 이제 n번째 묶음에서 화살표 방향으로 몇 번째 자리에 위치하느냐만 찾으면 분수 형식으로 출력 가능하게 됨을 알 수 있다!!
  • 물론 n번째 묶음에서 n이 짝수냐 홀수냐에 따라 화살표 방향이 다르기에 자리에 따른 분모와 분자의 값을 서로 다르게 해주어야 할 것이다.

1. 내 코드

num = int(input())
i = 1
sum = 1

while num > sum:
    i += 1
    sum += i

j = i
while num != sum:
    sum -= 1
    j -= 1

if i % 2 == 0:
    print(j, '/', i+1-j, sep='')
else:
    print(i+1-j, '/', j, sep='')

첫 번째 while문

  • 몇 번째 묶음인지 찾는 반복문이다. 반복 조건이 명확하기에 for문 보다 while문이 맞다.
  • 전 게시글인 벌집이랑 비슷하다고 보면 된다!
    num이 sum을 넘어가기 전까지가 해당 묶음에 포함된다고 보면 되고, i번째 묶음에 속하게 되는 것이다.
  • 물론 i=0, sum=0으로 시작해도 되긴 한다.
  • 벌집 문제와 마찬가지로 =에 유의하도록 하자. sum과 같은 수도 i번째 묶음에 포함되기 때문에 반복문을 한 번 더 돌면 안된다.
  • 또한 벌집 문제와 마찬가지로 i의 합과 sum의 합의 순서에 유의하자. sum은 i에 종속적이기에 순서를 주의해야 한다. sum은 1이 더해진 i를 더해야 하므로 i에 먼저 1을 더해야 하는 것이다.

두 번째 while문

  • j=1로 두고 구현할 수도 있을 것이다.
j = 1
while num != sum:
    sum -= 1
    j += 1

이렇게 말이다. 그러면 print문에서 홀수와 짝수의 위치만 바꾸면 되겠다. if i % 2 != 0 이렇게 한 줄만 !
그치만 그러면 j가 더 이상 j번째 자리라는 의미가 아니게 되는 것 같아 지금의 코드로 바꾸었다.

  • 아무튼 지금의 코드를 얘기해보자면, num은 결론적으로 sum보다 작다. 그래서 sum에서 1씩 빼 보아서 num과 일치하는 곳 즉, 해당 자리까지 찾아간다. 그게 i번째 줄에서 몇 번째 자리인지를 찾기 위해 j를 사용한 것이다.
  • i번째 줄은 결론적으로 i개만큼의 수가 있고 sum은 가장 마지막 수이니 뒤에서부터 우리가 찾는 수를 찾아가는 것이기 때문에 j를 i로 초기화시키고 여기서 하나씩 빼 가면 j번째 자리가 나오는 것이다.

출력문

  • 화살표 방향이 i가 짝수인지 홀수인지에 따라 바뀌기 때문에 출력문을 달리 해야 한다.
  • i가 짝수일 때를 보면, j는 분자를 따라가고 분모와 분자의 합은 i+1이라고 했으니 자동으로 분모는 i+1-j가 된다.
  • i가 홀수일 때는 j가 분모를 따라가니까 짝수일 때와 분모의 분자 위치를 달리 해주면 된다.

2. 정리된 코드

2-1. 두 번째 while문을 없애보자.

num = int(input())
i = 1
sum = 1

while num > sum:
    i += 1
    sum += i

j = sum - num + 1
if i % 2 != 0:
    print(j, '/', i+1-j, sep='')
else:
    print(i+1-j, '/', j, sep='')
  • 앞서 우리는 j를 반복문을 통해 sum과 num을 이용해서 구했는데 이 반복문을 사용하지 않고 하나의 식으로 표현 가능하다.
  • 원래는 j를 위 그림의 화살표 시작으로부터 얼마나 떨어져 있는지를 기준으로 구했다.
    이번에는 j를 i번째 묶음의 마지막 숫자로부터 얼마나 떨어져 있는지로 바꾸어보자. 그러면 당연히 num - sum이 될 것인데 sum으로부터 0번째 떨어진 것이 아닌 1번째 세므로 +1을 해서 sum - num +1이 되는 것이다.
  • 1번 방법과 방향이 완전히 반대 방향이므로 print문도 홀수와 짝수의 위치를 바꾸어 주자.

2-2. sum까지 없애보자.

num = int(input())
i = 0

while num > 0:
    i += 1
    num -= i

j = - num + 1
if i % 2 != 0:
    print(j, '/', i+1-j, sep='')
else:
    print(i+1-j, '/', j, sep='')
  • sum을 없앨 수도 있다는 사실을 발견하고 머리를 또 굴려 코드를 짜보았다.
  • 2-1과 아이디어는 동일하다. 똑같이 i번째 줄이며 j는 i번째 줄의 마지막 숫자로부터 얼마나 떨어졌냐이다.
  • 이번엔 sum을 이용하지 않고 바로 num에서 i를 빼주었다. i를 먼저 1 더하고 num에서 i를 빼주는 식으로 구현했기 때문에 i=0으로 초기화했다.
  • 그러면 num은 0이하의 수가 나올 것이다. 즉, 0이거나 음수이다. 0이면 해당 묶음의 가장 마지막 순서이고 그 외의 숫자는 2-1과 마찬가지로 마지막 수로부터 얼마나 떨어졌냐이다.
  • 그런데 음수이므로 우리는 이를 양수로 바꾸어 주어야 한다.
    예를 들어 -2가 j로 나왔다고 하자. 그러면 이건 그냥 말 그대로 뒤로 두 칸이다. 즉 이를 몇 번째인지로 나타내면 양수로 바꾸어주고 1을 더하면 되는 것이다.(2-1과 마찬가지로 1번째, 2번째..니까 1을 더하는 것)
  • 2-1과 마찬가지로 마지막 수로부터 얼마나 떨어졌냐이니까 print문의 짝수 홀수 위치는 그대로 유지된다.

출력문을 수정해보자.

나는 출력문이 int형과 문자열의 조합이라 +는 쓸 수 없어서

print(j, '/', i+1-j, sep='')

이런 식으로 썼는데,

print(f'{j}/{i+1-j}')

이렇게 쓸 수도 있었다..!
완저니 까먹고 있었넹ㅎ

결과

모두 걸리는 시간이 똑같다. while문은 시간에 큰 영향을 끼치지 않나보다.
내가 3가지의 코드를 작성해본 결과 2-2가 젤 별로인 것 같다.. 코드를 한 번에 이해하기가 쉽지가 않을 것이다. 짧은 게 가장 좋은 것만은 아닌 것 같다.
개인적으로 2-1가 가장 베스트 같다.

0개의 댓글