-
반응형
https://www.acmicpc.net/problem/9421
9421번: 소수상근수
양의 정수 n의 각 자리수의 제곱의 합을 계산한다. 그렇게 해서 나온 합도 각 자리수의 제곱의 합을 계산한다. 이렇게 반복해서 1이 나온다면, n을 상근수라고 한다. 700은 상근수이다. 72 + 02 + 02 =
www.acmicpc.net
풀이
먼저, N이하의 소수판별은 에라토스테네스의 체 알고리즘을 이용해서 소수를 판별했다.
[알고리즘] 소수판별 알고리즘 C++
0.목차 소수의 개념 소수판별1 (시간복잡도 O(N) 알고리즘) 소수판별2 (시간복잡도 O(√N) 알고리즘) 소수판별3 (시간복잡도 O(Nlog(logN)) 에라토스테네스의 체 알고리즘) 1. 소수(Prime Number) 의 개념 소
khu98.tistory.com
소수를 판별해나가면서, 해당 소수가 소수상근수인지 판별을 하는데, 해당숫자를 과정을 통과하다가 이전에 만났던 수를 만난다면, 무한루프를 돌고있다는 뜻이므로 소수상근수가 되지 못한다.
예를들어 문제에 나온 2를 예를들면,
2*2=4
4*4=16
1*1+6*6=37
3*3+7*7=58
5*5+8*8=89
8*8+9*9=145
1*1+4*4+5*5=42
4*4+2*2=20
2*2+0*0=4
4*4=16
1*1+6*6=37
.....
로 무한 반복을 돌기 때문에, 두번째 4*4=16에서 이미 소수상근수가 되지 못한다는것을 판별할 수 있다.
2는 소수상근수가 되지못한다는것을 알았는데, 다음소수들도 이처럼 하나하나 검사를 해야할까?
아니다. 해당 소수가 소수상근수가 되지 못하면, 해당소수를 소수상근수로 만드는 과정에서 만난 모든 수들은 결과적으로 소수상근수가 되지 못한다.
예를들어 어떤 수를 소수상근수로 만드는 과정에서 중간에 89가 튀어나왔다고 하자. 그럼 8*8+9*9=145 , 처럼 위의 무한루프에 끼어들기때문에, 소수상근수가 아닌 수가 지나왔던 모든 수들을 만나면 소수상근수를 만들지 못한다.
반대로 해당 소수가 소수상근수라면, 해당 소수를 소수상근수로 만드는 과정에서 만난 모든 수들은 결과적으로 소수상근수가 될 수 있다.
따라서 소수상근수가 될 수 있는 숫자의 배열과, 소수상근수가 될 수 없는 숫자의 배열을 선언해둔뒤,
해당 소수가 소수상근수라면, 소수상근수가 될 수 있는 숫자의 배열에 지금까지 지나왔던 모든 수들을 체크해주고,
해당 소수가 소수상근수가 아니라면, 소수상근수가 될 수 없는 숫자의 배열에 지금까지 지나왔던 모든 수들을 체크해준다.
그런뒤, 다음 소수를 체크할때, 위의 두 배열에 저장된 숫자중 하나를 만난다면, 바로 판별할 수 있기에 경우에 따라 true / false를 리턴해주면된다.
반응형코드
#include<iostream> #include<algorithm> #include<map> using namespace std; bool is_prime[1000001] = { 0 }; bool is_ok[1000001] = { 0 }; bool is_false[1000001] = { 0 }; map<int,bool> visited; bool sogen(int n) { while (n != 1) { if (is_ok[n]) { return true; } if (is_false[n]) { return false; } if (visited[n]) { for (auto k : visited) { is_false[k.first] =true; } return false; } visited[n] = true; int total = 0; while (n) { total += ((n % 10)*(n % 10)); n /= 10; } n = total; } for (auto k : visited) { is_ok[k.first] = true; } return true; } void solve(int n) { for (int i = 2; i <= n; i++) is_prime[i] = true; for (int i = 2; i <= n; i++) { if (is_prime[i]) { visited.clear(); if (sogen(i)) { cout << i << "\n"; } for (int j = i + i; j <= n; j += i) { is_prime[j] = false; } } } } int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n; cin >> n; solve(n); return 0; }
반응형'문제풀이 > 백준oj' 카테고리의 다른 글
[백준OJ] 3980번 선발 명단 (0) 2021.08.22 [백준OJ] 14600번 샤워실 바닥 깔기 (Small) (0) 2021.08.20 [백준OJ] 14425번 문자열 집합 (0) 2021.08.19 [백준OJ] 9935번 문자열 폭발 (0) 2021.08.18 [백준OJ] 11779번 최소비용 구하기 2 (0) 2021.08.17 댓글