셀프넘버 (self-number)

어떤 자연수 n이 있을 때, d(n)을 n의 각 자릿수 숫자들과 n 자신을 더한 숫자라고 정의하자.

예를 들어

d(91) = 9 + 1 + 91 = 101

이 때, n을 d(n)의 제네레이터(generator)라고 한다. 위의 예에서 91은 101의 제네레이터이다.

어떤 숫자들은 하나 이상의 제네레이터를 가지고 있는데, 101의 제네레이터는 91 뿐 아니라 100도 있다. 그런데 반대로, 제네레이터가 없는 숫자들도 있으며, 이런 숫자를 인도의 수학자 Kaprekar가 셀프 넘버(self-number)라 이름 붙였다. 예를 들어 1,3,5,7,9,20,31 은 셀프 넘버 들이다.

1 이상이고 5000 보다 작은 모든 셀프 넘버들의 합을 구하라.

박응용 3416

2020년 7월 7일 3:22 오후

목록으로
15개의 답변이 있습니다. 2 / 2 Page

다른 분들이 잘 해주셔서 저는 그냥 숏코딩으로 했습니다.
5000이 아니라 n일때 구하는 함수로 해보겠습니다.

def ans(n):
    s = lambda n: n+sum((int(i) for i in str(n)))
        return n*(n+1)//2 - set(s(i) for i in range(n+1) if s(i) <= n)

print(ans(5000))

이렇게 하면 1227365이 나오네요.
설명을 드리자면 그냥 노가다한거에요.
저도 파이썬을 혼자서 몇개월간 독학해서 많이 미숙합니다. 틀린부분있으면 지적해주세요.

insuhkim

2020년 9월 15일 2:43 오후

셀프 넘버가 아닌 숫자를 모으는 게 쉬우니 전체 합을 구하고 빼는 방식으로 계산해봤습니다.

d(n)을 정의하고

def gen_d(n):
    return sum([int(c) for c in str(n)] + [n])

1~ 4999의 합을 구합니다. 원래 (5000 * 4999)/2 인데 나누기 2를 식에 넣으니 double로 나와서 계산을 해버렸네요.
sum_all = 2500*4999

빈리스트를 정의 합니다. gen_d(n)에서 나오는 숫자를 모을겁니다.
unselfnums = []

d(n)의 값을 중복없이 모아서 합하고 전체 합에서 빼면 됩니다.

for i in range(1,4974):
    if not gen_d(i) in unselfnums:
        unselfnums.append(gen_d(i))

print(sum_all - sum(unselfnums))

크게 중요하지 않을수 있지만 ...
위에 4974가 어떻게 나왔는지 설명해드리자면
5000인 경우 무조건 d값이 5000을 넘을 텐데, 얼마까지 하는게 좋을구해봤습니다

우선 작은 쪽부터 생각해보면
미지의 네자리 숫자가 d값이 5000이 나오려면 5000 - 4 - 9 - 9 - 9 = 5000-31 = 4969 보다는 커야 합니다.
4969 보다 크면 무조건 5000이 넘는게 아니라 4969보다 적은 숫자들은 5000이 넘는지 아닌지 고민할 필요가 없다는 의미 입니다.
실제로 d(4969)는 4997입니다.

이번엔 위쪽으로 접근하면
49XX인경우 49가 고정이니 4987보다 크면 무조건 5000을 넘죠.
498X인 경우 498이 고정이고 4980일때 d값이 5001이라 497X이 어떻게 되는지 보면 되겠네요.
4970일때 4990이고 1이 증가하면 d값은 2가 증가합니다. 그러니 4975일때는 5000이고 4974 이후로는 볼필요가 없겠네요.

수학과 가지마세요 ^^ 때론 이런 고민안하는게 속편합니다.

obov

2020년 10월 12일 4:42 오후

def selfnum(sn,en) :
    a = set()
    for i in range(sn,en):
        a.add(i)

    for i in range(0,en):
        li = list(str(i))
        sli = 0
        for j in li:
            sli += int(j)
        i = i + sli
        a = a - {i}
    return a

a = sum(selfnum(1,5000))
print(a)

답 : 1227365

파이썬 초보입니다.

어떤숫자n의 제너레이터g는 어떤숫자n보다 작을수 밖에 없다.
라는 생각을 기본으로,
특정 범위의 숫자 전체를 set로 잡고, 0부터 set중 최대값 내에 속한 숫자(n)의 각자리숫자와 n의 합이 set에 존재한다면 그 숫자는 제너레이터가 있으니 삭제해가는 방식으로 구했습니다.

그래서 selfnum 함수는 sn이상 en미만 값을 입력으로 받으면
그 범위 내의 selfnumber의 set가 출력으로 나옵니다.

으라차차

M 2020년 12월 14일 9:40 오후

def d(n):        # D함수 
    return sum(i for i in [int(i) for i in str(n)]) + n
after_func_d = [d(i) for i in range(5000)]    #D함수의 결과물 
self_num = [i for i in range(5000) if i not in after_func_d]   #5000까지의 수중 D함수의 결과물이 아닌수 (셀프넘버)
print(sum(i for i in self_num))    # 셀프넘버의 합
# 1227365

저의 접근방법은 초등학교적인 방법이네요.
두 집합을 일단 다 구해 놓고...비교해서 소거... 그후 모두 더하기
코딩을 공부할때가 아니라 수학을 먼저 공부해야 겠네요.

sictomm

M 2021년 1월 30일 12:49 오전

def d(n):
    return sum(int(num) for num in str(n)) + n


print(sum({i for i in range(1, 5000)} - 
          {temp for n in range(1, 5000) if (temp := d(n)) < 5000}))

powerkid

M 2021년 12월 19일 8:46 오후