본문 바로가기

알고리즘/백준

[백준 알고리즘 자바]4673 : 셀프 넘버

수행일자 : 2021.08.11


https://www.acmicpc.net/problem/4673

 

4673번: 셀프 넘버

셀프 넘버는 1949년 인도 수학자 D.R. Kaprekar가 이름 붙였다. 양의 정수 n에 대해서 d(n)을 n과 n의 각 자리수를 더하는 함수라고 정의하자. 예를 들어, d(75) = 75+7+5 = 87이다. 양의 정수 n이 주어졌을 때,

www.acmicpc.net


문제

  • 셀프 넘버는 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