백준 9020: 골드바흐의 추측

Dahee Kim·2020년 12월 28일
2
시간 제한메모리 제한제출정답맞은 사람정답 비율
2 초256 MB2496910928858843.576%

문제


1보다 큰 자연수 중에서 1과 자기 자신을 제외한 약수가 없는 자연수를 소수라고 한다. 예를 들어, 5는 1과 5를 제외한 약수가 없기 때문에 소수이다. 하지만, 6은 6 = 2 × 3 이기 때문에 소수가 아니다.

골드바흐의 추측은 유명한 정수론의 미해결 문제로, 2보다 큰 모든 짝수는 두 소수의 합으로 나타낼 수 있다는 것이다. 이러한 수를 골드바흐 수라고 한다. 또, 짝수를 두 소수의 합으로 나타내는 표현을 그 수의 골드바흐 파티션이라고 한다. 예를 들면, 4 = 2 + 2, 6 = 3 + 3, 8 = 3 + 5, 10 = 5 + 5, 12 = 5 + 7, 14 = 3 + 11, 14 = 7 + 7이다. 10000보다 작거나 같은 모든 짝수 n에 대한 골드바흐 파티션은 존재한다.

2보다 큰 짝수 n이 주어졌을 때, n의 골드바흐 파티션을 출력하는 프로그램을 작성하시오. 만약 가능한 n의 골드바흐 파티션이 여러 가지인 경우에는 두 소수의 차이가 가장 작은 것을 출력한다.

입력


첫째 줄에 테스트 케이스의 개수 T가 주어진다. 각 테스트 케이스는 한 줄로 이루어져 있고 짝수 n이 주어진다. (4 ≤ n ≤ 10,000)

출력


각 테스트 케이스에 대해서 주어진 n의 골드바흐 파티션을 출력한다. 출력하는 소수는 작은 것부터 먼저 출력하며, 공백으로 구분한다.

예제


예제 입력 1
3
8
10
16

예제 출력 1
3 5
5 5
5 11

풀이


먼저 혼자 힘으로 문제를 풀어본 뒤, 다른 사람의 풀이를 보고 어떤 방법이 효율적일지 고민해보았다.

  • 내 풀이
    1) 두 소수 차이가 가장 적은 골드바흐 파티션을 구해야한다. 답은 첫째값, 둘째값으로 이루어져 있는데 첫째값을 입력값의 절반부터 시작해 1씩 감소시킨다.
    2) 첫째값이 소수인지 판별한다. 이때 2부터 '자기자신'-1까지 %연산을 한다. 0이 나오면 return false, 0이 나오지 않아 for문을 빠져나오면 return true.
    3) 만약 소수이면, 둘째값(입력값 - 해당값)이 소수인지 판별한다. 방식은 위에서와 같다.
    4) 만약 첫째값, 둘째값 모두 소수이면 결과를 출력한다.
#include <iostream>
using namespace std;

int T, num;

bool isPrimeNum(int num) {
	for (int i = 2; i < num; i++) {
		if (num % i == 0) return false;
	}
	return true;
}


int Answer(int num) {
	int length = num / 2;

	for (int i = 0; i < length; i++) {
		int temp1 = length - i;
		if (isPrimeNum(temp1)) {
			if (isPrimeNum(num - temp1)) {
				cout << temp1 << ' ' << num - temp1 << '\n';
				return 0;
			}
		}
	}

	return 1;

}

int main() {
	cin >> T;
	for (int i = 0; i < T; i++) {
		cin >> num;
		Answer(num);
	}
}
  • 찾아낸 풀이
    수가 소수인지 아닌지 판단하는 과정에서 차이가 존재한다.
    1) 일단 1부터 10000까지 소수를 구한다.
    2) 첫째값을 입력값의 절반부터 시작해 1씩 감소시킨다. 소수이면 둘째값이 소수인지 판별한다.
    3) 만약 첫째값, 둘째값 모두 소수이면 결과를 출력한다.
#include <iostream>
using namespace std;

int T;
int arr[10001] = { 0, }; // 0 = prime number, 1 = composite number


void isPrimeNum() {
	for (int i = 3; i < 10001; i++) {
		for (int j = 2; j < i; j++) {
			if (i % j == 0) arr[i] = 1;
		}
	}
}

int Answer(int num) {
	int length = num / 2;
	for (int i = 0; i < length; i++) {
		int temp1 = length - i;
		int temp2 = num - temp1;

		if (arr[temp1] == 0) {
			if (arr[temp2] == 0) {
				cout << temp1 << ' ' << temp2 << '\n';
				return 0;
			}
		}
	}
	return 1;
}

int main() {
	isPrimeNum();

	cin >> T;

	for (int i = 0; i < T; i++) {
		int num;
		cin >> num;
		Answer(num);
	}


}

소수 판별에 '에라토스테네스의 체' 적용한 풀이

추가로 소수 판별에 에라토스테네스의 체 알고리즘을 적용시키면 최적의 풀이가 탄생할 수 있을 것 같아 공부하고 추가했다.

소수 판별 방법에서 큰 차이가 존재한다.
1) 에라토스테네스의 체 알고리즘을 이용해 1부터 10000까지 소수를 구한다.
2) 첫째값을 입력값의 절반부터 시작해 1씩 감소시킨다. 소수이면 둘째값이 소수인지 판별한다.
3) 만약 첫째값, 둘째값 모두 소수이면 결과를 출력한다.

#include <iostream>
using namespace std;

int T;
int arr[10001] = { 0, }; // 0 = prime number, 1 = composite number

//에라토스테네스의 체
void isPrimeNum() {
	for(int i = 2; i<10001; i++){
		for (int j = i*2; j < 10001; j += i) {
			arr[j] = 1;
		}
	}
}

int Answer(int num) {
	//절반부터 탐색
	int length = num / 2;
	for (int i = 0; i < length; i++) {
		int temp1 = length - i;
		int temp2 = num - temp1;

		// 배열에 접근한 뒤, 둘 다 소수이면 출력
		if (arr[temp1] == 0) {
			if (arr[temp2] == 0) {
				cout << temp1 << ' ' << temp2 << '\n';
				return 0;
			}
		}
	}
	return 1;
}

int main() {
	isPrimeNum();

	cin >> T;

	for (int i = 0; i < T; i++) {
		int num;
		cin >> num;
		Answer(num);
	}

	return 0;

}

시간 단축 성공!

profile
하루가 너무 짧아~

0개의 댓글