문제
영문
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 |
댓글