문제
https://www.acmicpc.net/problem/9421
풀이(20분)
import java.io.*;
import java.util.*;
public class Main {
static int n;
static Set<Integer> yes = new TreeSet<>(); // 이전에 되는 것으로 확인이 되었던 값들
static Set<Integer> no = new HashSet<>(); // 이전에 안 되는 것으로 확인이 되었던 값들
static List<Integer> primes = new ArrayList<>(); // 소수 리스트
static Set<Integer> visited = new HashSet<>(); // 반복이 되는 것을 체크
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
n = Integer.parseInt(br.readLine());
isPrime();
for (int i : primes) {
visited.clear(); // 반복 집합 초기화
visited.add(i);
if (dfs(i)) {
yes.add(i);
}
}
StringBuilder sb = new StringBuilder();
for (int i : yes) {
if (i > n) {
break;
}
if (primes.contains(i)) {
sb.append(i).append("\n");
}
}
System.out.println(sb);
}
static boolean dfs(int num) { // 반복 탐색
int square = squareNum(num); // 제곱수
if (visited.contains(square)) { // 반복되는 것을 확인하고 있다면
return false; // 실패
} else {
visited.add(square);
}
if (square == 1) { // 1이라면 성공
yes.add(num);
return true;
}
if (yes.contains(square)) { // 되었다면 체크
return true;
}
if (no.contains(square)) { // 불가능하다면 체크
return false;
}
boolean flag = dfs(square);
if (flag) {
yes.add(num);
} else {
no.add(num);
}
return flag;
}
// 에라토스테네스의 체
static void isPrime() {
boolean[] isPrime = new boolean[n + 1];
Arrays.fill(isPrime, true);
isPrime[0] = isPrime[1] = false;
for (int i = 2; i <= Math.sqrt(n); i++) {
if (!isPrime[i]) {
continue;
}
for (int j = i * i; j <= n; j += i) {
isPrime[j] = false;
}
}
for (int i = 2; i <= n; i++) {
if (isPrime[i]) {
primes.add(i);
}
}
}
// 제곱 수 확인
static int squareNum(int num) {
int squareNum = 0;
while (num / 10 > 0) {
squareNum += (num % 10) * (num % 10);
num /= 10;
}
squareNum += num * num;
return squareNum;
}
}
문제 풀이 전략
전체 흐름 요약
- 입력값 n을 받음
→ 1 ~ n 범위 안의 수 중에서 확인을 진행합니다. - 에라토스테네스의 체로 소수 목록 생성
→ primes 리스트에 모든 소수를 저장합니다. - 각 소수에 대해 ‘상근수(Happy Number)’ 판별 수행
- 상근수: 각 자리의 제곱을 반복해서 더했을 때 결국 1이 되는 수
- 예: 7 → 49 → 97 → 130 → 10 → 1 ✅
상근수 판별 로직 (dfs)
- visited: 이미 계산한 숫자를 저장해 순환(무한 반복) 방지
- yes: 이미 상근수로 판정된 숫자
- no: 상근수가 아닌 것으로 판정된 숫자
- 현재 수의 각 자리 제곱의 합을 계산 (squareNum)
- 이미 방문한 적 있는 수라면 → 순환 발생 → 실패 (false)
- 결과가 1이라면 → 상근수 성공 (true)
- 이미 성공(yes)이나 실패(no)로 판정된 값이면 그대로 결과 반환
- 그 외의 경우 → 재귀 호출로 계속 탐색
- 탐색 결과에 따라 현재 숫자를 yes 또는 no 집합에 저장합니다.
출력
모든 소수 중에서 n 이하인 수 중 yes 집합(상근수)에 포함된 값만 출력합니다.
'문제 풀이 > 백준' 카테고리의 다른 글
| [백준] 1966번. 프린터 큐(Kotlin) (0) | 2025.10.14 |
|---|---|
| [백준] 17490번. 일감호에 다리 놓기(JAVA) (0) | 2025.10.12 |
| [백준] 18115번. 카드 놓기(JAVA) (0) | 2025.10.11 |
| [백준] 21314번. 민겸 수(JAVA) (0) | 2025.09.01 |
| [백준] 19638번. 센티와 마법의 뿅망치(JAVA) (2) | 2025.09.01 |