
문제
영문
By listing the first six prime numbers: 2, 3, 5, 7, 11, and 13, we can see that the 6th prime is 13.
What is the 10 001st prime number?
한글
소수를 크기 순으로 나열하면 2, 3, 5, 7, 11, 13, ... 과 같이 됩니다.
이 때 10,001번째의 소수를 구하세요.
해설
파이썬 (Python) + 수학적 해석
방법 1
소수란 1또는 자기 자신으로밖에 나누어 떨어지지 않는 수를 뜻합니다. 그러니 자기 자신보다 작거나 같은 수로 모두 나눠본 다음, 자기 자신으로밖에 나누어지지 않는다면 그 수는 소수입니다!
prime_th = 0 n = 1 while prime_th<10001: n += 1 x = 2 while x<n: if n%x == 0: break x += 1 if x == n: prime_th += 1 print(n)
위 아이디어를 통해 반복문으로 자기보다 작은 수로 모두 나누기 시도를 하는 코드입니다. 하지만 이 방법은 굉장히 느립니다. \
방법 2
def isPrime(n): if n in (2,3): return True elif not n%6 in (1,5): return False div_check = 5 #6k + 5 꼴부터 시작 sqrt_n = int(n**(1/2)) while div_check <= sqrt_n: # 제곱근 이하의 수만 탐색 if n%div_check == 0: #6k + 5꼴 return False div_check += 2 if n%div_check == 0: #6k + 1꼴 return False div_check += 4 return True
이제 방법 1에서 계산 횟수를 줄여봅시다.
우선 첫 번째로 나누어 떨어지는지 탐색시 제곱근 이하의 수만 탐색해주어도 됩니다. 왜냐하면 어떤 수가 제곱근 이하의 수로 나누어 떨어지지 않는다면, 그 이상의 수로도 나누어 떨어지지 않을 테니까요.
(이는 귀납법으로 간단하게 증명 가능합니다. 어떤 수가 제곱근 이상의 수로 나누어 떨어진다면, 원래 수를 그 수로 나누면 몫은 제곱근 이하가 될 것입니다. 하지만 제곱근 이하의 수로 나누어 떨어지지 않는다 가정했으면 이는 모순입니다.)
두 번째로는 6으로 나눈 나머지가 1이거나 5인 수만 탐색해주어도 됩니다. 왜냐하면 다른 경우의 수는 모두 2 또는 3으로 나누어지는 경우니까요.
prime_th = 2 target_th = 10001 n = 5 #2,3은 소수인지 아니까 5부터 시작 # 이후 계속 6k+5, 6k+1꼴을 탐색 answer = 0 while answer == 0: # 6k+5 if isPrime(n): prime_th += 1 if prime_th == target_th: answer = n n += 2 # 6k+1 if isPrime(n): prime_th += 1 if prime_th == target_th: answer = n n += 4 print(answer)
이후 다음과 같이 비슷하게 6k+5 또는 6k+1 꼴인 숫자만을 탐색해주시면 됩니다.
방법 3
target_th = 10001 n = 5 prime_list = [2,3] is_add2 = True # 2와 4를 번갈아서 더하는 역할 while len(prime_list) < target_th: sqrt_n = int(n**(1/2)) prime_i = 0 # prime_list에서 쓰는 index is_prime = True while prime_list[prime_i] <= sqrt_n: if n%prime_list[prime_i] == 0: is_prime = False break prime_i += 1 if is_prime: prime_list.append(n) if is_add2: #6k+5꼴 일때는 2 더하기 n += 2 is_add2 = False else: #6k+1꼴 일때는 4 더하기 n += 4 is_add2 = True print(prime_list[-1])
소수 목록을 리스트에 저장해 두고, 리스트에 있는 소수로만 나누어보고 판별하는 법도 있습니다! 나누기를 좀 더 적게 시도할 수 있다는 장점이 있지만, 메모리를 많이 차지한다는 단점이 있습니다.
(추가로 코드가 반복되는게 싫어 2와 4를 더해주는 부분은 플립플롭?식으로 만들어봤습니다)
C
#include<stdio.h> int main(void) { int ptest=2, pcount=0; long ncount = 1; while (pcount < 10001) { ncount++; ptest = 2; while (ptest <= ncount) { if (ncount%ptest == 0) { if (ncount == ptest) { pcount++; } break; } ptest++; } } printf("%ld", ncount); }
방법 1을 구현한 코드입니다. C라서 그런지 빠르게 결과가 나오네요.
정답
104743
'🖥️ 문제 풀이 > 프로젝트 오일러' 카테고리의 다른 글
[프로젝트 오일러] 문제9 - 특별한 피타고라스 트리플 (0) | 2022.09.28 |
---|---|
[프로젝트 오일러] 문제8 - 시리즈에서 가장 큰 곱 (0) | 2022.09.10 |
[프로젝트 오일러] 문제6 - 합 제곱 차 (0) | 2022.09.09 |
[프로젝트 오일러] 문제5 - 최소공배수 (0) | 2022.09.09 |
[프로젝트 오일러] 문제4 - 가장 큰 대칭수 (0) | 2022.09.09 |
댓글