Programmers : https://programmers.co.kr/learn/courses/30/lessons/42839

 

코딩테스트 연습 - 소수 찾기

한자리 숫자가 적힌 종이 조각이 흩어져있습니다. 흩어진 종이 조각을 붙여 소수를 몇 개 만들 수 있는지 알아내려 합니다. 각 종이 조각에 적힌 숫자가 적힌 문자열 numbers가 주어졌을 때, 종이 �

programmers.co.kr

 

한자리 숫자가 적힌 종이 조각이 흩어져있습니다. 흩어진 종이 조각을 붙여 소수를 몇 개 만들 수 있는지 알아내려 합니다.

각 종이 조각에 적힌 숫자가 적힌 문자열 numbers가 주어졌을 때, 종이 조각으로 만들 수 있는 소수가 몇 개인지 return 하도록 solution 함수를 완성해주세요.

 

programmers level 2 소수찾기 문제입니다.

 

예를 들어서 문제를 설명하겠습니다.

 

예제에 있는 "17"의 경우 1, 7을 이용해서 수를 만들 수 있고

이 때 소수를 만들 수 있는 경우는 7, 17, 71 이렇게 3가지입니다.

 

결국 String이 주어지면 각 자릿수를 이용해서 모든 수를 조합해보고, 소수를 만들 수 있는 경우가 몆개냐! 를 묻습니다.

 

이 문제를 풀기 위해서 에라토스테네스의 체 알고리즘을 사용했습니다.

이정도 알고리즘은 기본 중의 기본이니 꼭 사용할 줄 아셔야합니다.

(에라토스테네스 :  https://junho0956.tistory.com/35)

 

좀 더 소수에 근접하게 수를 빠르게 만들 수 있는 방법이 있을까 고민해봤는데.. 떠오르질 않더라구요

그래서 완전탐색과 같이 모든 경우의 수에 접근했습니다.

 

저는 DFS를 이용해서 아래와 같이 접근했습니다! (백트래킹 이라고 할 수 있겠네요)

 

dfs(현재까지 만든 수, 더 사용할 수 있는 수)

 

dfs 과정마다 현재까지 만든 수를 소수인지 확인해주는 작업을 꼭 해주시고,

같은 수가 중복될 수 있으니 찾은 숫자는 따로 처리해주세요!

 

설명은 주석을 달아놓았으니, 보시면 바로 이해되실껍니다~

#include <string>
#include <vector>
#include <iostream>
#define e7 10000000 // e7 : 1e7이 사용이 안되서 만들었어요. 1천만 입니다
using namespace std;

bool sosu[e7]; // 소수는 e7까지 접근가능합니다
bool find_it[e7]; // 소수를 찾은 경우 사용했음을 나타내기 위해 사용합니다
bool use[7]; // 각 자리수에 접근할 녀석이에요
string str; // 스트링은 전역으로 사용했습니다

void make_eratos() { // 에라토스테네스의 체
    for (int i = 2; i < e7; i++) sosu[i] = true;
    for (int i = 2; i * i < e7; i++)
        if (sosu[i])
            for (int k = i * i; k < e7; k += i) sosu[k] = false;
}

int dfs(int make_num, int able) { // 탐색부분
    // 더이상 사용할 수 있는 수가 없으면 소수인지 바로 판단해주세요
    if (!able) {
        if (sosu[make_num]) {
            if (find_it[make_num]) return 0;
            find_it[make_num] = 1;
            return 1;
        }
        else return 0;
    }
    
    int ret = 0;
    // 항상 현재까지 만든 수가 소수인지 확인하는 작업!
    if (sosu[make_num] && !find_it[make_num]) find_it[make_num] = 1, ret++;

    for (int i = 0; i < str.size(); i++) { // 모든 수에 접근합니다.
        if (!use[i]) { // i번째 자리수를 사용안했다면?
            int join_num = make_num; // 새로운 수를 만들어주세요
            join_num *= 10;
            join_num += str[i] - '0';
            use[i] = 1; // 이 자리를 사용했음을 나타냅니다
            ret += dfs(join_num, able - 1);
            use[i] = 0; // 이 자리의 사용이 끝났음을 나타냅니다
        }
    }

    return ret;
}

int solution(string numbers) {

    str = numbers;
    make_eratos(); // 일단 소수부터 만들게요
    return dfs(0, numbers.size());

}

'algorithm > programmers' 카테고리의 다른 글

Programmers 카펫 C++  (0) 2020.07.03
Programmers 숫자 야구 C++  (0) 2020.07.03
Programmers 라면공장(C++)  (0) 2020.07.02
programmers N으로 표현  (0) 2020.03.12
programmers 전화번호 목록  (0) 2020.03.10

+ Recent posts