수행일자 : 2021.08.11
https://www.acmicpc.net/problem/4673
문제
- 셀프 넘버는 1949년 인도 수학자 D.R. Kaprekar가 이름 붙였다. 양의 정수 n에 대해서 d(n)을 n과 n의 각 자리수를 더하는 함수라고 정의하자.
- 예를 들어, d(75) = 75+7+5 = 87이다. 양의 정수 n이 주어졌을 때, 이 수를 시작해서 n, d(n), d(d(n)), d(d(d(n))), ...과 같은 무한 수열을 만들 수 있다.
- 예를 들어, 33으로 시작한다면 다음 수는 33 + 3 + 3 = 39이고, 그 다음 수는 39 + 3 + 9 = 51, 다음 수는 51 + 5 + 1 = 57이다. 이런식으로 다음과 같은 수열을 만들 수 있다.
- n을 d(n)의 생성자라고 한다. 위의 수열에서 33은 39의 생성자이고, 39는 51의 생성자, 51은 57의 생성자이다. 생성자가 한 개보다 많은 경우도 있다. 예를 들어, 101은 생성자가 2개(91과 100) 있다.
- 생성자가 없는 숫자를 셀프 넘버라고 한다. 100보다 작은 셀프 넘버는 총 13개가 있다. 1, 3, 5, 7, 9, 20, 31, 42, 53, 64, 75, 86, 97
- 10000보다 작거나 같은 셀프 넘버를 한 줄에 하나씩 출력하는 프로그램을 작성하시오.
입력
- 입력은 없다.
출력
- 10,000보다 작거나 같은 셀프 넘버를 한 줄에 하나씩 증가하는 순서로 출력한다.
입출력 예제
BufferedReader 와 함수, 배열 등을 사용해서 풀어보았다.
문제 이해에만 몇 일이 걸렸다...
셀프 넘버란 양의 정수 n에 대해서 d(n)을 n과 n 각 자리수를 더하는 함수라고 정의하자. 라는 말은
예를 들어 56이라는 숫자가 있으면 이 값을 d(n) 이라는 함수에 넣어서 나오는 결과값이 56 + 5 + 6 = 67 을 한 67이라는 값이라는 것을 의미한다.
바로 다음 문징이 이해에 오랜시간이 걸린 이유이다.
- 다음에 나오는 무한수열이라는 단어와 그 아래에서 연속적으로 계산을 해주는 예시를 보고 숫자 하나를 입력하면 10,000이 되기 전까지 계속해서 계산이 이루어져야 한다고 생각을 했다.
- 33을 함수에 넣어서 나오는 값이 39가 아니라 9993이 된다고 생각한 것이다.
- 그렇다보니 셀프 넘버에 대한 정의가 불가능했던 것이다.
- 하나의 숫자가 함수에 들어가서 결과값이 나오면 해당 함수는 역할을 끝낸 것이다.
- 1부터 10,000보다 작거나 같은 수까지 하나씩 입력을 받게 되고, 입력받은 각각의 수에 대해 함수가 1번씩 실행된다.
- 예제 출력을 참고하여 적어보자면 아래와 같다.
- 1이라는 수를 입력받고 함수에 돌린 결과가 2
- 2라는 수를 입력받고 함수에 돌린 결과가 4
- 3이라는 수를 입력받고 함수에 돌린 결과가 6
그렇다면 이제 본격적으로 문제 풀이에 들어가보자.
선언할 변수는 다음과 같다.
- 1부터 10,000 까지의 true / false 값을 담을 배열 arr[]
- 함수를 실행한 결과값을 담을 변수 result
- 입력받는 값을 저장할 변수 num
- while문을 돌면서 결과값을 저장할 변수 sum
먼저 셀프 넘버를 만들어주는 함수를 작성해보자. (함수명은 개인이 원하는대로 지으면 된다.)
필자는 checkNumber 라고 정의했다. int 형으로 입력받는 값, 즉 1 부터 10,000 까지의 값이 저장될 변수 [ num ] 을 파라미터 값으로 가진 int 형으로 리턴되는 함수이다.
함수를 선언했으면 [ sum ] 이라는 변수를 선언하고, 이 변수에 [ num ] 값을 넣어준다.
num이 0이 아닐때까지 수행하는 while 문을 작성하고, 그 안에서 결과값과 자리수에 대한 식을 정의한다.
- sum 이라는 변수에는 입력받은 값과 해당 값의 각 자리수의 값이 더해져야 한다.
- num % 10 을 하면 나머지인 자리수가 나오게 되고
- num / 10 을 하면 몫인 자리수가 나오게 된다.
- 257로 예시를 들어보면 아래와 같다.
- 257 % 10 = 7 > sum = 257 + 7 (264)
- 257 / 10 = 25 > num = 25
- 25 % 10 = 5 > sum = 264 + 5 (269)
- 25 / 10 = 2 > num = 2
- 2 % 10 = 2 > sum = 269 + 2 (271)
이렇게 각 입력받은 값과 각 자릿수를 더하는 식을 구현하고 결과값인 셀프넘버가 10,000보다 작거나 같아야하므로 함수를 수행한 결과값이 10,000이 넘었을 때에는 break;를 하여 빠져나올 수 있도록 if문을 하나 추가한다.
함수가 다 작성이 되었으면 이제 함수를 실행할 메인으로 가보자.
먼저 boolean 형으로 arr[] 배열을 선언해준다. 이 때, 배열의 크기는 1부터 10,000 까지여야 하므로 10,001 이 되어야 한다.
다음으로는 1부터 10,000까지 도는 for문을 작성한다. 이 for 문은 입력받을 수만큼 도는 것으로, 1부터 10,000까지의 수를 입력받는 것과 같은 역할을 한다.
- 실제로 수를 입력받는 Scanner 나 BufferedReader 같은 역할을 하는 것이 아니라, 1부터 10,000까지 돌면서 각 수를 함수에 넣어 결과를 출력한다는 의미이다.
해당 for 문 안에서 함수를 실행한다.
여기에서 10,000 보다 작은 값이면 출력이 되어야하기에 해당 값들을 true 로 선언하는 if문을 하나 추가해준다.
다음으로는 1부터 배열의 크기만큼 도는 for 문을 하나 선언한다.
이 for 문은 결과값을 출력하는 용도이기에 1 ~ 10,000 까지 돌며 배열이 false 이면 해당 값을 출력한다.
- 함수가 수행되어서 결과값이 나왔다는 것은 즉 셀프 넘버가 아니라는 것이므로 배열에 값이 false 로 존재한다.
- 그러므로 false 인 값을 출력하는 것이 바로 셀프 넘버를 출력하는 것이다.
답안 소스
public class Main {
public static void main(String[] args) {
boolean arr[] = new boolean[10001];
for(int i=1; i<=10000; i++) {
int result = checkNumber(i);
if(result<=10000) {
arr[result] = true;
}
}
for(int i=1; i<arr.length; i++) {
if(!arr[i]) {
System.out.println(i);
}
}
}
public static int checkNumber(int num) {
int sum = num;
while(num!=0) {
sum = sum + (num % 10);
num = num / 10;
if(sum > 10000) {
break;
}
}
return sum;
}
}
'알고리즘 > 백준' 카테고리의 다른 글
[백준 알고리즘 자바]11654 : 아스키 코드 (0) | 2021.08.20 |
---|---|
[백준 알고리즘 자바]1065 : 한수 (0) | 2021.08.14 |
[15596]정수 N개의 합 (0) | 2021.08.04 |
[4344]평균은 넘겠지 (0) | 2021.08.01 |
[8958]OX퀴즈 (0) | 2021.08.01 |