목차
백준 단계별로 풀어보기
25.11.12
15단계: 약수, 배수와 소수 2
17103번: 골드바흐 파티션
문제 링크 : https://www.acmicpc.net/problem/17103
문제를 풀기 위해 알아야 할 개념
>> 소수 판별 함수
: 아래 글에 정리해두었다.
소수 판별 함수 만들기
목차합성수의 특성: 합성수 N에 대하여 N = a × b 라고 하면, a와 b 둘 중 하나는 √N 보다 작거나 같다.--> 이를 활용하면 N이 소수인지 확인할 때, 1부터 √N까지만 반복하여 N을 나눈 나머지가 0이
mobics.tistory.com
>> 에라토스테네스의 체
: 수학에서 특정 범위 내의 소수를 판별할 때, 가장 빠르고 쉬운 방법이다.
--> 1부터 n 까지의 소수를 알고 싶다면 합성수의 특성에 의해 n = a × b 라면, a와 b 중 적어도 하나는 √n 이하이므로 √n 이하의 소수의 배수를 지우고 남은 수가 소수이다.
- 소수를 구하는 과정
: 아래 과정은 1부터 120까지의 소수를 찾는 과정이다.
- 2부터 소수를 구하고자 하는 구간의 모든 수를 나열한다. (아래 이미지에서 회색)
- 2는 소수이므로 오른쪽에 2를 쓰고, 2를 제외한 2의 배수를 모두 지운다. (아래 이미지에서 빨간색)
- 남아있는 수 가운데 3은 소수이므로 오른쪽에 3을 쓰고, 3을 제외한 3의 배수를 모두 지운다. (아래 이미지에서 초록색)
- 남아있는 수 가운데 5는 소수이므로 오른쪽에 5를 쓰고, 5를 제외한 5의 배수를 모두 지운다. (아래 이미지에서 파란색)
- 남아있는 수 가운데 7은 소수이므로 오른쪽에 7을 쓰고, 7을 제외한 7의 배수를 모두 지운다. (아래 이미지에서 노란색)
- 위의 과정을 반복하면 구하는 구간의 모든 소수가 남는다. 이를 오른쪽에 쓴다. (아래 이미지에서 보라색)
--> 이 예시의 경우, 11² > 120 이므로 11보다 작은 소수의 배수들만 지워도 충분하다. 즉, 120보다 작거나 같은 수 가운데 2, 3, 5, 7의 배수를 지우고 남는 수는 모두 소수이다.
※ 이해를 위한 이미지

※ 참고 문서 - 위키백과
에라토스테네스의 체 - 위키백과, 우리 모두의 백과사전
위키백과, 우리 모두의 백과사전. 에라토스테네스의 체 수학에서 에라토스테네스의 체는 소수를 찾는 빠르고 쉬운 방법이다. 고대 그리스 수학자 에라토스테네스가 발견하였다. 2부터 소수를
ko.wikipedia.org
- 코드
- Enumerable.Repeat() 을 통해 isPrime 배열의 모든 값을 true로 만들어서 초기화한 다음, 0과 1은 소수가 아니므로 값을 false로 바꾼다.
- for 반복문을 통해 2부터 √num 까지 반복하여 isPrime[i] 값이 true 라면 i × i 부터 시작하여 모든 배수의 배열값을 false로 바꾼다.
- i × i 부터 시작하는 이유는 i 의 배수 i × k 에 대해 k < i 인 경우는 이미 앞의 과정에서 이미 지워져있기 때문이다.
- ex) i = 5 일 때, 5 × 2 = 10 은 2를 처리할 때, 5 × 3 = 15 는 3을 처리할 때, 5 × 4 = 20 은 4를 처리할 때 이미 false 가 되어있다.
- 찾은 소수 배열을 반환한다.
using System.Linq;
private bool[] IsPrime(int num)
{
bool[] isPrime = Enumerable.Repeat(true, num + 1).ToArray();
isPrime[0] = isPrime[1] = false;
for (int i = 2; i * i <= num; i++)
{
if (isPrime[i])
{
for (int j = i * i; j <= num; j += i)
{
isPrime[j] = false;
}
}
}
return isPrime;
}
※ 공식 문서 - Enumerable.Repeat
Enumerable.Repeat<TResult>(TResult, Int32) 메서드 (System.Linq)
반복되는 단일 값이 들어 있는 시퀀스를 생성합니다.
learn.microsoft.com
문제 풀이
: 문제의 시간제한이 0.5초이므로, 시간을 줄이기 위해 우선 정수 N의 최댓값인 1,000,000 까지의 모든 소수를 찾아서 HashSet에 저장해둔다. 그리고 두 소수의 순서만 다른 것은 같은 파티션이기 때문에 소수 a, b 에 대해 입력값 N = a + b 이라면, a ≤ N/2 까지만 반복하면서 a와 N - a 가 모두 HashSet에 있는지 확인하면 된다.
- StreamReader로 입력값을 받아 int값으로 변환하여 테스트 케이스의 개수를 담을 변수 t 에 담는다.
- 찾은 소수를 담을 HashSet인 primeHash 를 초기화하고 for 반복문을 통해 2부터 정수 N의 최댓값까지 반복하면서 만든 소수 판별 함수를 통해 모든 소수를 primeHash 에 추가한다. --> 가장 작은 소수가 2이므로 2부터 시작하고, 2 외에 짝수는 소수일 수 없으므로 반복할 때 1,000,000는 포함하지 않아도 된다.
- for 반복문을 통해 각각의 테스트 케이스마다 골드바흐 파티션의 수를 찾는다.
- StreamReader로 입력값을 받아 int값으로 변환하여 정수 N을 담을 변수 input 에 담고, 골드바흐 파티션의 수를 담을 변수 result 를 0으로 초기화한다.
- for 반복문을 통해 2부터 input / 2 까지 반복하면서 j 와 input - j 가 모두 primeHash 에 있다면 골드바흐 파티션에 해당하므로 result 를 1 증가시킨다.
- result 값을 StringBuilder에 담는다.
- StreamWriter로 StringBuilder에 담은 값을 출력한다.
정답 코드
using System.IO;
using System.Text;
class Backjoon
{
static void Main(string[] args)
{
using var sr = new StreamReader(Console.OpenStandardInput());
using var sw = new StreamWriter(Console.OpenStandardOutput());
StringBuilder sb = new StringBuilder();
int t = int.Parse(sr.ReadLine());
HashSet<int> primeHash = new HashSet<int>();
for (int i = 2; i < 1000000; i++)
{
if (IsPrime(i))
{
primeHash.Add(i);
}
}
for (int i = 0; i < t; i++)
{
int input = int.Parse(sr.ReadLine());
int result = 0;
for (int j = 2; j <= input / 2; j++)
{
if (primeHash.Contains(j) && primeHash.Contains(input - j))
result++;
}
sb.AppendLine(result.ToString());
}
sw.Write(sb.ToString());
}
static bool IsPrime(int num)
{
if (num == 1) return false;
if (num == 2) return true;
if (num % 2 == 0) return false;
int limit = (int)Math.Sqrt(num);
for (int i = 3; i <= limit; i += 2)
{
if (num % i == 0) return false;
}
return true;
}
}
└ 에라토스테네스의 체 사용버전
: 에라토스테네스의 체를 사용하여 소수를 판별하는 함수 IsPrime() 을 만들어서 사용하였다.
>> 코드
using System.IO;
using System.Text;
using System.Linq;
class Backjoon
{
static void Main(string[] args)
{
using var sr = new StreamReader(Console.OpenStandardInput());
using var sw = new StreamWriter(Console.OpenStandardOutput());
StringBuilder sb = new StringBuilder();
int t = int.Parse(sr.ReadLine());
bool[] isPrime = IsPrime(1000000);
for (int i = 0; i < t; i++)
{
int input = int.Parse(sr.ReadLine());
int result = 0;
for (int j = 2; j <= input / 2; j++)
{
if (isPrime[j] && isPrime[input - j])
result++;
}
sb.AppendLine(result.ToString());
}
sw.Write(sb.ToString());
}
static bool[] IsPrime(int num)
{
bool[] isPrime = Enumerable.Repeat(true, num + 1).ToArray();
isPrime[0] = isPrime[1] = false;
for (int i = 2; i * i <= num; i++)
{
if (isPrime[i])
{
for (int j = i * i; j <= num; j += i)
{
isPrime[j] = false;
}
}
}
return isPrime;
}
}'Development > Baekjoon' 카테고리의 다른 글
| [C#] 28278번: 스택 2 (0) | 2025.11.14 |
|---|---|
| [C#] 13909번: 창문 닫기 (0) | 2025.11.13 |
| [C#] 4948번: 베르트랑 공준 (0) | 2025.11.11 |
| [C#] 1929번: 소수 구하기 (0) | 2025.11.10 |
| [C#] 4134번: 다음 소수 (0) | 2025.11.09 |