BOJ | 4673번

송치헌·2021년 6월 23일
0
post-thumbnail

Python 풀이

def d(n): #생성자를 이용하여 새로운 수를 만드는 생성 함수
    sum = n #결과값은 원래 자신의 수 + 각 자릿수의 합이므로 자리수를 더하기 전에 원래 자기 자신을 저장해준다.
    while n!=0: #n을 10으로 계속 나눠가며 몫과 나머지 저장. n을 10으로 나눈 몫을 다시 n으로 저장해주면 결국 1의 자리까지 다 나눴을 때 n은 0이된다.
        q = n//10 #몫
        r = n%10  #나머지
        n = q     #n을 다시 몫으로 저장(원래 수에서 일의 자리수가 빠진 숫자가 된다.)
        sum += r  #일의 자리수 저장
    return sum    #새로운 숫자 리턴

a = [i for i in range(1,10001)] #1부터 10000까지 리스트 a에 저장
for i in range(1,10001): #양의 정수이고 10000이하의 수 중에서 셀프 넘버를 찾는 문제이므로 1에서 10000까지만 반복
    if d(i) in a: #생성한 숫자가 리스트 a에 있으면
        a.remove(d(i)) #그 숫자를 삭제 (d함수로 만들어진 숫자는 생성자를 가진 수이므로 셀프 넘버가 아니라서 삭제해주면 결국 리스트에는 셀프 넘버만 남게된다.)

for i in a : print(i) #셀프 넘버 출력

d(n)은 어떤 숫자(생성자)를 이용하여 새로운 숫자(생성자를 가진 숫자)를 만드는 함수이다. n을 10으로 계속 나눠가며 나머지를 원래 숫자에 반복문이 끝날 때까지 더해준다. 그러다 보면 일의 자리수가 계속 더해지는 것을 볼 수 있다. (직접 계산해 보면 나올 것이다.)

그 다음 1부터 10000까지 리스트(a)에 저장해 놓고 다시 1부터 10000까지 차례로 함수 d에 넣어서 생성된 숫자를 리스트 a와 비교하면서 리스트에 있으면 리스트에서 그 숫자를 제외시킨다.(생성자를 통해 만들어진 숫자는 셀프 넘버가 아니므로 제외시킨다.) 이 과정을 1부터 10000까지 하다보면 셀프 넘버만 남게 된다.

아래는 set을 이용하여 푸는 방법이다. 위의 코드는 248ms가 나왔지만 set을 이용하면 80ms가 나왔다.

def d(n):
    sum = n
    while n!=0:
        q = n//10
        r = n%10
        n = q
        sum += r
    return sum

a = set([i for i in range(1,10001)])
b = set()
for i in range(1,10001):
    b.add(d(i))

for i in sorted(a-b) : print(i) #수학에서 차집합과 같다. 집합 a에서 a와 b의 교집합을 제외한 집합(셀프 넘버만 남는다.)

C++ 풀이

#include <iostream>

using namespace std;

int d(int n) {
    int sum = n;
    while (n) {
    	sum += n % 10;
    	n /= 10;
    }
    return sum;
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    bool check[11111] = { false, }; //check리스트를 만든다.

    for (int i = 1; i <= 10000; i++) {
   	check[d(i)] = true; //새로 생성된 수의 인덱스 번호는 true로 스위칭해준다.
    }
    for (int i = 1; i <= 10000; i++) {
    	if (!check[i]) cout << i << '\n'; //인덱싱 결과 false면 그 인덱스 번호를 출력(셀프 넘버만 출력된다.)
    }
}
profile
https://oraange.tistory.com/ 여기에도 많이 놀러와 주세요

0개의 댓글