소수찾기

원래벌레·2022년 11월 24일

문제


문제의 시간복잡도

현재 n의 값은 7입니다. 이런 경우의 문제에서는 시간복잡도를 따지지 않고 풀어도 된다 생각을 했습니다.


문제의 접근법

문제에서 구해야 하는 것은 크게 두가지 입니다.

첫번째 : 주어진 문자열을 통해서 만들 수 있는 모든 경우의수
두번째 : 이렇게 구한 조합의 수가 소수인지 아닌지의 판가름

모든 경우의수 구하기
이를 구하기 위하여 사용한 것은 DFS입니다.
그래프의 깊이 탐색을 통하여 추가 및 다음 요소를 추가 해주는 방식으로 진행을 했습니다.

예시를 한번 들어 보겠습니다.
numbers.size() 값이 4일때에 그래프의 모습입니다.

여기에 예시로 numbers = "1234" 일 때 1을 먼저 추가 했을 때를 기준으로 그래프의 노드 값을 채운 결과를 보여드리겠습니다.

먼저 1은 추가가 되었습니다. 이런 1은 추가적으로 2,3,4를 추가 할 수 있을 것입니다. 그렇기 때문에 노드로 2,3,4를 가집니다.

그리고 Level=2 에서 노드 2,3,4는 또 각각이 위의 사진의 Level=3의 노드들을 뒤에 추가를 할 수 있을 것입니다.

그리고 마지막으로 Level=3의 노드들은 Level=4의 노드들을 가질 수 있을 것입니다,

여기서 답은 다 나왔습니다.

이제 이 노드를 Level1부터 Level4까지 이동을하면서 각각의 값을 추가해주면 되겠습니다.

한가지 예시만을 들어보겠습니다.

빨간 화살표는 탐색을 하는 과정입니다.
위의 그래프에서 먼저 1을 탐색을 할 것입니다. 그렇다면 이 1을 배열에 저장을 합니다.
현재 그러면 배열은 [1] 의 상태일 것입니다.

그리고 다음은 2를 탐색을 할 것입니다. 이 때, 1에 2를 붙혀줍니다.
그러면 그 값은 12가 되고 이것을 배열에 추가를 합니다.
그러면 배열은 [1,12]가 될 것입니다.

그리고 그다음은 3을 추가해서 [1,12,123]

그리고 그다음은 4를 추가해서 [1,12,123,1234] 이런 결과를 얻을 수 있게 됩니다.

위와 같은 방법으로 탐색하지 않은 노드들을 모두 탐색을 하면 결과적으로 모든 원소의 값을 얻을 수 있습니다.

소수
소수를 구하는 방법은 쉽습니다.
일단 소수란 1과 자기자신을 제외한 그 어떤 수도 약수로서 같지 않는 수를 이야기 합니다.

그래서 이 소수를 구히기 위해서는 2부터 자기자신 전 까지의 수로 모듈 연산을 하여 그값이 0이 아닌지를 판단하면 됩니다.

근데 이렇게하면 n번을 돌아야 그 결과를 알 수 있으므로 이를 줄이기 위하여 n에 루트를 씌워서 다시 같은 연산을 해줄 때, 같은 연산 결과를 얻을 수 있습니다.

왜냐하면 수는 X * Y로 값을 구 할 수 있습니다. 그래서 어떤 수를 구할 때의 약수는 짝이 지어지고 그 짝은 결국 루트를 씌웠을 때 왼쪽 값들만을 비교 할 수 있습니다.


풀이

#include <string>
#include <vector>
#include <set>
#include <iostream>
#include <cmath>

using namespace std;

vector<int> v;
set<int> s;

void dfs(int x, int y,bool check[])
{

    for(int i=0;i<v.size();i++)
    {
        if(check[i]==false)
            break;
        else
        {
            if(v.size()-1 == i)
                return;
        }
    }
    
    bool f_check[7];
    copy(check,check + 7, f_check);
    int a = (x*10)+v[y];
        
    
    s.insert(a);
    f_check[y] = true;
    
    for(int i=0;i<v.size();i++)
    {
        if(f_check[i] == false)
            dfs(a, i, f_check);
    }
}


int solution(string numbers) {
    int answer = 0;
    
    for(int i=0;i<numbers.size();i++)
        v.push_back(numbers[i]-48);
    
    bool check[7] = {false, };

    
    for(int i=0;i<numbers.size();i++)
        dfs(0,i,check);
    
    for(auto i=s.begin() ;i != s.end();i++)
    {   
        bool flag = true;
        cout << (*i) << " ";
        for(int j=2;j<=sqrt((*i));j++)
        {
            if((*i)%j == 0)
            {
                flag=false;
                break;
            }
        }
        if(flag==true && *i!=0 && *i!=1) answer++;
        
            
    }
        
    return answer;
}

1) numbers의 각 char 요소들을 int형으로 변환하여 vector에 저장을 하였다.

2) 그리고 check라는 배열을 두어 false로 초기화를 하였다.

3) numbers 요소들을 저장했던 vector의 각 요소들에 대하여 for문을 돌면서 dfs를 실행하였다.

4) int형을 저장하는 set 컨테이너를 하나 생성하였다.
( 중복된 값은 저장되지 않게 하기 위해서 )

5) dfs는 먼저 check 배열을 확인한다. check 배열이 모두 true라면 모든 찢겨진 종이를 다 사용 했다는 것이다.

6) 그리고 dfs의 인수로 받은 numbers의 한 요소를 뒤에 이어 붙혀주고 set에 값을 추가한다.

7) 다시 check값이 false인 것에 한하여 dfs를 재귀적으로 해준다.
( 그래프로 따지면 자식노드를 추가해주는 것이다. )

8) 이렇게 모든 경우의 수가 들어가 있는 set의 모든 요소를 확인하여 소수인지를 판가름 한다.


기타

"copy"

copy( 복사할배열의주소, 배열의주소+어디전까지복사하는가, 결과를넣을배열의주소);

c++은 배열을 인수로 넣을 때 배열의 주소가 들어가므로, 인수의 값을 복사해서 사용 하고 싶은 경우 위와같은 copy 함수를 사용 할 수 있다.

profile
학습한 내용을 담은 블로그 입니다.

0개의 댓글