반응형
DoZZang
Do IT
DoZZang
전체 방문자
오늘
어제
  • Programming
    • Git
    • Web
    • 기타
    • Python
      • CodeUp
    • Math
    • Algorithm
    • Baekjoon
    • C,C++
    • Life
      • 독서
      • Just
      • 영화

블로그 메뉴

  • 홈
  • 태그
  • 방명록

인기 글

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
DoZZang

Do IT

[C] 백준 2090번 : 골드바흐의 추측
Baekjoon

[C] 백준 2090번 : 골드바흐의 추측

2023. 1. 31. 20:24
반응형

https://www.acmicpc.net/problem/9020

 

9020번: 골드바흐의 추측

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

www.acmicpc.net

시간이 0.5초나 되는 코드입니다.

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
int isPrimeNumber(int x);	//소수 판별 함수 선언

int main() {
	int N, T, x = 0;
	scanf("%d", &T);
	for (int i = 0; i < T; i++) {
		scanf("%d", &N);
		int* arr = (int*)malloc(sizeof(int) * (N + 1));	//배열의 index를 실제 값으로 생각할 것이기 때문에 배열의 크기는 (N+1)
		for (int j = 2; j <= N / 2; j++) {	// N / 2까지 범위를 설정함으로써 j <= (N - j)가 성립되어 작은 소수부터 출력
			arr[j] = isPrimeNumber(j);	//isPrimeNumber함수에 의해 index가 소수라면 배열의 값을 1로 초기화
			if (arr[j] == 1 && isPrimeNumber(N - j) == 1)	//j가 소수로 확정났다면 다른 한 수 N-j만 소수면 됨
				x = j;										//반복문이 계속 돌기 때문에 결국 합을 구성하는 소수의 차가 가장 적게 될 것.
		}
		printf("%d %d\n",x, N - x);
		free(arr);	//1차원 배열 동적할당 해제
	}

	return 0;
}


int isPrimeNumber(int x) {
	double length;
	length = sqrt(x);
	for (int i = 2; i <= length; i++) {
		if (x % i == 0) return 0;	//소수가 아니면 0을 리턴
	}
	return 1;	//소수는 1을 리턴
}

자꾸 시간초과가 나서 애먹은 문제입니다.

반드시 이중반복문으로 풀어야합니다. 삼중반복문으로 코드를 구성한다면 시간초과가 나타납니다.삼중반복문을 쓰지 않고 어떻게 풀어야하지?가 주된 고민이었습니다.

 

1. N+1개 만큼의 일차원배열을 동적할당하여 소수라면 배열의 값을 1로 초기화하였고 배열의 인덱스로 어떤 수인지 구분할 수 있도록 하였습니다.(12번줄)

 

2. 2~N/2까지 반복문을 돌려 그 수가 소수인지 판별하는 함수를 이용하여 소수를 판별하였습니다.

여기서 삼중반복문으로 가지않으려면 판별에서 끝내면 안되었습니다.

 

 N에 대한 두 소수의 합을 구하는 문제이기 때문에

하나의 수를 구했을 경우, 나머지 수는 자연스럽게 n-(구해진수)로 고정시킬 수 있었습니다.

=> O(n^2) > O(n)으로 시간복잡도 감소

 

위 아이디어를 이용하여  isPrimeNumber(j)가 소수라고 판별되었다면 N-j가 소수인지 바로 판별을 해줍니다.

N-j도 소수라면 정답의 후보가 됩니다.

반복문의 루프는 계속 N/2까지 돌기 때문에 결국 마지막에 변수 x에 저장되는 값이 두 소수의 차가 가장 적을 때일 것입니다.

-> 범위가 N/2인 이유는 j가 N - j보다 커지는 상황을 미연에 방지하기 위해서 입니다.

 

0.5초나 걸려 0.1초 미만으로 코드를 짜신 분을 찾아보았다.

#include <stdio.h>

int main() {
    int T;
    scanf("%d", &T);
    for (int t = 0;t < T;t++) {
        int n;
        scanf("%d", &n);
        int i, j;
        int arr[10001] = { 1,1, };

        for (i = 2; i * i <= 10001; i++)
            if (arr[i] == 0)
                for (j = i * i; j <= 10001; j += i)
                    arr[j] = 1;

        int l = n / 2, r = n / 2;
        while (1) {
            if (arr[l] == 0 && arr[r] == 0) {
                printf("%d %d\n", l, r);
                break;
            }
            l--;
            r++;
        }
    }
    return 0;
}	yacyj님의 코드

N의 범위가 크지 않은 10,000으로 주어졌었던 것을 생각하면 굳이 동적할당할 이유가 없었다.

while문이 굉장히 인상적이었는데 저렇게도 할 수 있겠구나..하는 생각도 들었다.

반응형
저작자표시 (새창열림)

'Baekjoon' 카테고리의 다른 글

[C] 백준 2750번 : 수 정렬하기  (1) 2023.02.02
[C] 백준 2563번 : 색종이  (0) 2023.02.01
[C]백준 2566번 : 최댓값  (0) 2023.01.29
[C] 백준 2738번 : 행렬 덧셈  (2) 2023.01.27
[C] 백준 1929번 : 소수 구하기  (0) 2023.01.27
    'Baekjoon' 카테고리의 다른 글
    • [C] 백준 2750번 : 수 정렬하기
    • [C] 백준 2563번 : 색종이
    • [C]백준 2566번 : 최댓값
    • [C] 백준 2738번 : 행렬 덧셈
    DoZZang
    DoZZang
    과정은 힘들지만 성장은 즐겁습니다.

    티스토리툴바