본문바로가기
[오일러 프로젝트] 조커: 상상 그 이상의 대칭수
수학동아 2020.02.21

 

코.알.못 홍 기자의 코딩 도전기

코딩의 ‘코’자도 모르는 코.알.못. 홍 기자가 수학 문제를 코딩으로 푸는 오일러 프로젝트 문제를 하나하나 해결해 나갈 예정입니다. 오일러 프로젝트는 수학과 프로그래밍 실력을 모두 키울 수 있도록 2001년에 만든 수학 문제 웹사이트로, 수학 문제를 프로그래밍으로 해결하는 게 목적이지요. 홍 기자와 함께 한다면 수학과 파이썬 모두 정복할 수도…? 같이 한번 풀어봐요!

 

 

영화 ‘조커’의 주인공 아서 플렉은 광대 일을 하며 코미디언을 꿈꿉니다. 하지만 모두가 미쳐가는 코미디같은 세상에서 점점 악당의 모습으로 변해가죠. 그런데 그 일이 실제로 일어났습니다. 한 오일러 프로젝트 문제 때문이었죠. 이 기사를 읽고 있는 독자 여러분, 앞으로 저를 ‘홍커’라고 불러줄래요?

 

 

<오일러 프로젝트 4번 문제>

앞에서부터 읽거나 뒤에서부터 읽을 때 모양이 같은 수를 ‘대칭수’라고 부릅니다.

예를 들어 두 자릿수를 곱해 만들 수 있는 대칭수 중 가장 큰 수는 91×99=9009입니다.

그럼 세 자릿수를 곱해 만들 수 있는  가장 큰 대칭수는 얼마일까요?

 

 

이번 문제는 대칭수에 관한 문제로, 먼저 세 자릿수 2개를 곱하는 반복문은 'for' 명령어와 'range' 함수를 이용해 만들 수 있습니다. 하지만 어떤 수가 대칭수인지 판별하려면 원래 수와 뒤집은 수가 같은지 일일이 확인해봐야 하지요. 파이썬의 자료형 중 하나인 '문자열'을 이용해 문제를 풀어볼게요!

 

 

파이썬 완전정복! 필수 명령어

 

1. 숫자를 문자열로 바꾸기

4번 문제에서는 숫자를 문자열로 바꾼 다음 뒤집어 대칭수인지 확인할 거예요. 같은 123이라도 문자열로 정의하면 뒤집기가 더 쉽거든요. 이때 문자열은 수와 다르게 작은따옴표를 사용해 나타냅니다. 숫자를 문자열로 바꾸는 함수는 ‘str’입니다. 예를 들어 숫자 123을 문자열 ‘123’으로 바꾸는 명령어는 아래와 같이 씁니다.

 

 

2. 문자열을 마음대로 자르고 뒤집기

‘잘라낸다’라는 의미가 있는 ‘슬라이싱(slicing)’ 표기법을 이용해 문자를 뒤집을 수 있습니다. 슬라이싱 표기법은 (문자열 변수의 이름)[시작 번호:끝 번호:step]으로 나타냅니다. 만약 시작 또는 끝 번호를 따로 지정하지 않으면 각각 처음과 마지막 문자로 정해지죠. 이때 문자를 뒤집기 위해서 제일 마지막에 있는 ‘step’을 이용해야 합니다.

step은 숫자의 간격을 의미하는데요, 예를 들어 왼쪽 첫 번째 문자를 기준으로 5, 10, 15번째 문자를 출력하고 싶다면 step을 5로 정하면 됩니다. 여기서 step을 -1로 지정하면 방향을 오른쪽에서 왼쪽 방향으로 읽어 출력하라는 뜻이 됩니다. 즉, 문자열을 뒤집을 수 있죠.

 

 

 

TIP 1. ★오류 지뢰밭★ 알려드려요!

① 자료가 문자열임을 파이썬에 꼭 알려줘야 할 땐 잊지 말고 꼭 작은 따옴표를 붙여 주세요!

​​​​② 슬라이싱 표기법으로 원하는 문자열을 골라낼 때, 당연하지만 문자열의 길이보다 큰 값을 시작과 끝 번호로 지정하면 오류가 납니다.

 

TIP 2.  슬라이싱 표기법을 활용할 때, 문자열을 읽는 방향에 따라 시작과 끝 번호를 정해줘야 합니다. 만약 왼쪽에서 오른쪽으로 가는 방향이라면 ‘시작 번호<끝 번호’여야겠지요. 마찬가지로 step이 음수, 즉 오른쪽에서 왼쪽으로 읽으려면 ‘시작 번호>끝 번호’여야 합니다.

 

 

도전! 오일러 프로젝트 4번 문제 뽀개기

* 코딩 언어는 Python으로 두고 실행하세요!

 

 

#1, 2, 3 앞의 명령어를 이용해 대칭수인지 판별하는 is_palindrome(n) 함수를 만듭니다.

#4 조건문을 만들어 원래와 뒤집은 문자열이 같다면 참을 돌려줍니다.

#5 만약 문자열이 같지 않아 대칭수 조건을 만족하지 않으면 거짓을 돌려줍니다.

#6 구해야 할 답을 0으로 두고 시작합니다.

#7, 8 곱해야 할 세 자릿수 a, b의 범위를 지정합니다.

#9 대칭수인지 판별해야 할 세 자릿수 두 개의 곱을 p로 정합니다.

#10 가장 큰 대칭수를 찾아야 하므로, 기존에 나온 곱셈 결과 이상의 수만 나오도록 합니다.

#11 10번째 줄의 조건을 만족하는 대칭수 p의 값을 변수 ans에 대입합니다.

#12 가장 큰 대칭수를 출력합니다.

 

 

Bonus! 오일러 퀴즈

오일러 프로젝트 4번 문제를 위 코딩창에서 풀어보고, 다음 예제 문제에도 도전해 보세요!

 

1. 네 자릿수의 곱으로 만들 수 있는 가장 큰 대칭수를 찾아보자.

2. 세 자릿수의 곱으로 만든 수 중에서 처음과 마지막 숫자가 같은 가장 큰 수를 찾아보자.

 

 

 

저는 이번 문제를 문자열로 바꿔 풀었지만

숫자 상태에서 대칭수인지 판별하는 코드를 짤 수 있지 않을까요?

좋은 아이디어가 있다면 댓글을 남겨 코.알.못 홍아름 기자를 도와주세요!

 

  •  
    mathwizard Lv.7 2020.02.25

    대칭수! 흥미로운 주제네요.

    댓글 작성하기 좋아요0 댓글수3
    •  
      홍아름 기자 Lv.2 2020.03.05

       

      다음달에 다뤄질 주제도 많이 기대해주세요~!

       

      좋아요0
    •  
      Lv.10 2020.03.11

      다음 번의 주제는

      1 ~ 20 사이의 어떤 수로도 나누어 떨어지는 가장 작은 수 

      이군요 ㅎㅎ

      좋아요0
    •  
      홍아름 기자 Lv.2 2020.03.26

       

      1~20 사이의 어떤 수로도 나눠 떨어지는 가장 작은 수를 구하는 문제는 이미 다뤘답니다~!

      (http://www.polymath.co.kr/contents/view/7998?page=1)

      오일러 프로젝트 문제 순서보다는, 제가 풀 수 있는 (코딩이 비교적 쉬운) 문제들을 먼저 풀고 있거든요ㅎㅎ

      다음 문제도 기대해주세요! (이미 게시판에 올라왔지만요ㅎ)

       

      좋아요0
  •  
    disciple Lv.5 2020.02.26

    is_palindrome(n) 함수에서 반환 값을 정할 때 if 문을 쓰지 않고

    조건을 반환 값으로 남기면 반환 값은 조건이 맞는지 틀린지에 따라 True 혹은 False로 지정됩니다.

    즉,

    def is_palindrome(n):
        s = str(n)
        r = s[::-1]
        if s == r: return True
        else: return False

    위의 코드를

    def is_palindrome(n):
        s = str(n)
        r = s[::-1]
        return s == r

    로 단순화시킬 수 있고, 여기서 다시

    def is_palindrome(n):
        return str(n) == str(n)[::-1]

    로 단순화가 가능합니다.

     

    이 두 줄을 lambda 문으로 한 줄으로 단순화가 가능합니다.

    lambda 문은 이름 없는 함수를 만드는 명령어로,

    한 함수에서 매개변수를 받고 반환하는 작업만 할 때 이 함수를 lambda 문으로 표현할 수 있습니다.

    기본적으로

    lambda 매개변수1, 매개변수2, ... 매개변수n: 함수 반환 값

    형식으로 쓰입니다.

    이를 변수에 집어 넣으면 그 변수의 값은 lambda 문이 표현한 함수가 됩니다.

    예를 들어서,

    someFunction = lambda x: x + 1

    lambda 문을 사용한 위 코드는 아래 코드와 정확히 같은 효과를 냅니다.

    def someFunction(x):

        return x + 1

    그러므로 is_palindrome(n) 함수는

    is_palindrome = lambda n: str(n) == str(n)[::-1]

    으로 최종적으로 단순화가 가능합니다.

    댓글 작성하기 좋아요0 댓글수2
    •  
      disciple Lv.5 2020.02.26

      참고로 코드를 최대로 단순화시키면

      ans = 0
      for a in range(100, 1000):
          for b in range(100, 1000):
              if a * b > ans and str(a * b) == str(a * b)[::-1]: ans = a * b
      print(ans)

      이 됩니다.

      if a * b > ans and str(a * b) == str(a * b)[::-1]: ans = a * b  에 설명을 조금 덧붙이자면,

      is_palindrome 함수의 반환 값을 직접적으로 if 문에 집어넣은 것 뿐입니다.

      그래서 이제 is_palindrome 함수는 필요하지 않습니다.

      좋아요0
    •  
      홍아름 기자 Lv.2 2020.03.05

       

      disciple 친구, 긴 댓글 남겨줘서 고마워요!

      알려준 내용을 참고해서 다음엔 더 짧으면서 빨리 문제를 풀 수 있는 코드를 고민해볼게요! 고마워요~

       

      좋아요0
  •  
    Krbx(켋) Lv.6 2020.03.06

    저는 C언어를 쓰기 때문에 제 기준으로 설명드리자면

    변수를 int(정수꼴)로 받고 나눗셈을 하면 나머지가 튀어나오기도 합니다.

    즉 int a=3, b=2; 해놓고

    printf("%d",a/b); 하면 1.5가 아니라 1이 나옵니다.

     

    이를 이용해서 (그리고 세자리*세자리중 가장 큰수이므로 아마도 6자리일거기 때문에)

    for구문 이용해서 세자리*세자리꼴 해놓고

    그 수를 10만으로 나눈 값과 그 수를 1로 나눈 값의 차

    그 수를 1만으로 나눈 값과 그 수를 10으로 나눈 값의 차

    그 수를 1000으로 나눈 값과 그 수를 100으로 나눈 값의 차

    이 셋이 모두 10으로 나눴을때 나머지가 0이다

    이거 만족하는 수들 리스트 뽑아서 그중에서 가장 큰수 골랐던거 같네요

    댓글 작성하기 좋아요0 댓글수3
    •  
      홍아름 기자 Lv.2 2020.03.26

       

      오, 생각보다 많은 친구가 파이썬보다는 C언어를 다루고 있네요?

      C언어도 한번 배워볼까요? 파이썬보다 많이 어려운가요?

       

      좋아요0
    •  
      Krbx(켋) Lv.6 2020.03.26

      많이 어렵지는 않습니다만, 파이썬하고 비교하자면 조금은 더 어렵습니다.

      그래도 저도 c언어를 잘하는 편은 아닌데(많이 하지도 않았고요), 오일러 프로젝트 1번부터 9번까지는 정말 쉽게 풀 수 있습니다.

      초보가 조언을 드리자니 웃기지만, 기자님도 한번 배워보시면 좋을것 같네요. 다른 언어들이 다 그렇듯, 불붙으면 정말 재밌습니다.

      좋아요0
    •  
      홍아름 기자 Lv.2 2020.03.31

       

      오... 그럼 파이썬도 어렵지만(쿨럭) 같이 C언어도 조금씩 공부해볼게요!

      앞으로도 파이썬과는 다르게 C언어로는 어떻게 문제를 해결할 수 있는지, 댓글 달아주세요~!

      고마워요~~~

       

      좋아요0