개발공부/코테
[백준 1929: 소수 구하기] 파이썬 풀이
sohee!
2023. 11. 16. 00:48
1929번: 소수 구하기
첫째 줄에 자연수 M과 N이 빈 칸을 사이에 두고 주어진다. (1 ≤ M ≤ N ≤ 1,000,000) M이상 N이하의 소수가 하나 이상 있는 입력만 주어진다.
www.acmicpc.net
문제
M이상 N이하의 소수를 모두 출력하는 프로그램을 작성하시오.
입력
첫째 줄에 자연수 M과 N이 빈 칸을 사이에 두고 주어진다. (1 ≤ M ≤ N ≤ 1,000,000) M이상 N이하의 소수가 하나 이상 있는 입력만 주어진다.
출력
한 줄에 하나씩, 증가하는 순서대로 소수를 출력한다.

💻 코드
import sys
input = sys.stdin.readline
m, n = map(int, input().split()) # m부터 n까지의 소수 구하기
is_prime = [True] * (n + 1) # n+1 크기로 각 숫자가 소수인지를 판단하는 is_prime 배열
for i in range(2, int(n**(1/2))+1):
if is_prime[i]: #i가 소수이면
for j in range(i+i, n+1, i): #i의 배수를 소수가 아니라고 바꿈
is_prime[j] = False
is_prime[1] = False # 1은 무조건 소수가 아님
#출력
for i in range(m, n+1):
if is_prime[i]:
print(i)
'에라토스테네스의 체' 알고리즘 설명을 그대로 구현하였습니다.
- n+1 크기로 각 숫자가 소수인지를 판단하는 is_prime 생성
- 2부터 루트n까지 반복문을 돌면서, (루트n을 사용하는 이유는 아래 에라토스테네스 체 설명 참고)
- i가 소수이면 (is_prime[i]가 True이면)
- i의 배수들을 모두 소수가 아니라고 바꿈 (is_prime[i]를 False라고 바꿈)
- is_prime 배열의 값이 True이면 소수인 것이므로 출력
✏️ 풀이
에라토스테네스의 체
- 2부터 소수를 구하고자 하는 구간의 모든 수를 나열한다. 그림에서 회색 사각형으로 두른 수들이 여기에 해당한다.
- 2는 소수이므로 오른쪽에 2를 쓴다. (빨간색)
- 자기 자신을 제외한 2의 배수를 모두 지운다.
- 남아있는 수 가운데 3은 소수이므로 오른쪽에 3을 쓴다. (초록색)
- 자기 자신을 제외한 3의 배수를 모두 지운다.
- 남아있는 수 가운데 5는 소수이므로 오른쪽에 5를 쓴다. (파란색)
- 자기 자신을 제외한 5의 배수를 모두 지운다.
- 남아있는 수 가운데 7은 소수이므로 오른쪽에 7을 쓴다. (노란색)
- 자기 자신을 제외한 7의 배수를 모두 지운다.
- 위의 과정을 반복하면 구하는 구간의 모든 소수가 남는다. (보라색)
그림의 경우,
이므로 11보다 작은 수의 배수들만 지워도 충분하다. 즉, 120보다 작거나 같은 수 가운데 2, 3, 5, 7의 배수를 지우고 남는 수는 모두 소수이다.
에라토스테네스의 체 - 위키백과, 우리 모두의 백과사전
위키백과, 우리 모두의 백과사전. 에라토스테네스의 체 수학에서 에라토스테네스의 체는 소수를 찾는 방법이다. 고대 그리스 수학자 에라토스테네스가 발견하였다. 알고리즘[편집] 2부터 소수
ko.wikipedia.org
⚠️ 잘못된 풀이 _ 시간초과
1차 시도
import sys
input = sys.stdin.readline
m, n = map(int, input().split()) # m부터 n까지의 소수 구하기
result = list(range(m, n))
for i in range(m, n):
for j in reversed(range(2, i-1)):
if i%j == 0 and i in result:
result.remove(i)
print(*result, sep=" ")
- 그냥 보자마자 생각나는대로 풀었는데 사실 풀면서도 오 시간초과 나겠는데? 하면서 풀었다..
- 풀이 방법
- m부터 n까지 정수로 이루어진 result 수열을 생성
- 해당 숫자보다 작은 숫자로 나누었을 때 0이 되면 소수가 아니다 → 소수가 아니므로 result 수열에서 제거
2차 시도
import sys
input = sys.stdin.readline
m, n = map(int, input().split()) # m부터 n까지의 소수 구하기
is_prime = [True] * (n + 1)
for i in range(m, n):
for j in range(2, i):
if i%j == 0:
is_prime[i] = False
break
if is_prime[i]:
print(i)
- 시간을 좀 줄여볼 수 없을까 하다가 result 배열을 없애고 is_prime 배열을 만들어봤음 + break 문 추가
- 그래도 시간초과…. 이중반복문 부분이 문제인 것 같아서 '에라토스테네스의 체' 알고리즘을 공부하여 풀이했다.