qqqqq1212   1년 전

작성한 코드입니다. 어떤 원리로 작성했는지 간단히 설명드리면

1. 에라토스테네스의 체로 소수 분류

2. 분류된 소수 중 2개의 소수의 합으로 입력받은 n값과 비교

3. 식이 성립할 수 있는 소수의 차에 대해 기준을 절대값으로 뺄셈의 최소값 확인.

4. 절대값이 가장 작은 idx를 바탕으로 소수 출력.

위와 같은 큰 틀로 코드를 작성하였는데,

다른 분들 코드를 보면 절반을 기준으로 +1, -1 을 하여 소수를 판별하시는 과정을 거치셨는데,

현재 9% 정도에서 시간초과가 뜨는데, 그 풀이과정 말고 제가 작성한 코드 중에서 코드 진행 시간을 줄일 수 있는 방법이 있을까요 ?

yup0927   1년 전

1. 매 테스트 케이스마다 소수 판정을 새로 하고 있습니다.

소수 판정 전처리를 for문 밖으로 꺼내시면 중복 계산을 안 할 수 있습니다.

2. 확인을 이중으로 하고 있습니다.

32~41번 줄에서, 예시로 n이 8인 상황을 가정하자면 3 + 5와 5 + 3으로 매 판정을 두 번씩 하게 됩니다.

간단하게는 l = 0이 아닌 l = k로 고쳐주신다면 피할 수 있겠습니다.


2-1. 조금 더 생각해보면 먼저 나오는 케이스보다 나중에 나오는 케이스가 차이가 더 작을 거라고 생각할 수 있겠습니다.
즉, rst에 저장하고 다시 훑어서 최솟값을 찾는 과정이 있지만 rst에 마지막으로 들어간 값이 항상 문제가 원하는 케이스기 때문에 애초에 값을 하나만 갖고 있어도 됩니다.


3. 47~60번 줄은 이미 확인한 결과를 다시 계산하면서 찾고 있습니다. 즉 이미 32~41번 줄에서 한 작업을 또 하고 있습니다.

2, 2-1와 함께 묶어서 생각해보자면 32~60번 줄을 아래와 같이 고칠 수 있겠습니다.

int a, b;
for (int k = 0; k < cnt; ++k) {
    for (int l = k; l < cnt; ++l) {
        if (realPrime[k] + realPrime[l] == n) {
            a = realPrime[k], b = realPrime[l];
        }
    }
}
cout << a << ' ' << b << '\n';

(여기서 조금 더 생각해본다면, 어차피 작은 소수부터 확인했을 때 제일 마지막에 나오는 케이스가 답이라면

큰 소수부터 확인했을 때 제일 처음에 나오는 케이스가 답이라는 말이 되겠습니다.

다른 분들의 코드가 절반 기준으로 탐색하는 이유가 이 때문입니다.)

4. realPrime[k] + realPrime[l] > n이라면 굳이 더 탐색할 이유가 없습니다.

if(realPrime[k] + realPrime[l] > n) break;를 걸어주시면 시간이 더 줄어듭니다.


이 외에도 줄이는 방법은 더 있습니다만 (여전히 확인하는 시간이 오래 걸림) 일단 여기까지 적겠습니다.

댓글을 작성하려면 로그인해야 합니다.