Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

25-yuyu0830 #92

Merged
merged 3 commits into from
Sep 2, 2024
Merged

25-yuyu0830 #92

merged 3 commits into from
Sep 2, 2024

Conversation

yuyu0830
Copy link
Collaborator

🔗 문제 링크

신기한 소수

✔️ 소요된 시간

50분

✨ 수도 코드

❓ 문제

image


❗ 풀이

첫 접근이 바로 떠오르지가 않았다. 어떤 식으로 풀어야할까? 8자리 소수를 어떻게 처리해야할까 고민을 좀 했다.

처음 생각한건 자릿수 별로 소수를 정리하는 것이였다. 정리한 뒤 n자리수가 되도록 조합해서 정리하는 것이었다.

하지만 그렇게 하면 8자리의 경우 8자리 소수까지 모두 구할 필요가 있었다. 각 자리수 별로 O(log n) 만큼 구해야 하니까 O(n log n) 이 되고, 99,999,999 에 대한 n log n 이기 때문에 2초 안에 풀 수가 없다.
애초에 메모리도 4MB기 때문에 저걸 다 저장하면서 할 수가 없다..


그 다음 떠오른 생각은 앞자리부터 소수인지 확인하며 수를 확장하는 방법이다.

문제에서는 4자리, 3자리, 2자리 이렇게 줄어들며 소수인지 확인하기에 바로 떠오르지 않았지만 반대로 1자리부터 소수인지 확인한다면 확인해야하는 수의 범위가 확연히 줄어든다.

맨 앞자리 수부터 소수인지 확인한 뒤, 소수인 수를 vector에 저장한다. 이렇게 하면 vector에 있는 수들은 전부 소수가 된다.

vector에 있는 수들을 하나씩 꺼내서 맨 뒤에 0~9까지 숫자를 붙여본 뒤, 다시 소수인지 확인하며 원하는 n의 자리까지 확인해보면 된다.

이렇게 하면 확인해야하는 수의 범위가 아주아주 줄어든다. 특히 수가 커질 수록 소수일 가능성이 낮아지므로 수가 적어진다.

소스코드

#include <iostream>
#include <math.h>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

bool notPrime[10000] = {0, };

bool isPrime(int t) {
    for (int i = 2; i <= sqrt(t); i++) {
        if (notPrime[i]) continue;
        if (t % i == 0) {
            notPrime[i] = true;
            return false;
        }
    }
    return true;
}

int main() {
    int n; cin >> n;

    int start = 1;

    vector<int> v[2];
    bool e = false;

    v[1].push_back(0);
    
    for (int i = 0; i < n; i++) {
        for (int p : v[!e]) {
            for (int t = 0; t < 10; t++) {
                int cur = p * 10 + t;
                if (isPrime(cur)) v[e].push_back(cur);
            }
        }

        v[!e].clear();
        e = !e;
    }

    for (int i : v[e]) 
        printf("%d\n", i);
}

📚 새롭게 알게된 내용

Copy link
Collaborator

@InSange InSange left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요점만 바로 잡는다면 쉽게 해결할 수 있었던 문제였던 것 같습니다.
저의 경우 DFS로 풀어봤는데 위의 풀이 방식처럼 소수인 것들만 배열에 집어넣으면서 뒤집어가며 마치 전기통닭구이와 같은 느낌?으로 탐색하는 방식도 있군요.
재밌는 풀이 방식이였습니다.

v[1].push_back(0);

for (int i = 0; i < n; i++) {
for (int p : v[!e]) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분을 처음 봤을 때 무엇인가 했습니다.
이제는 여러번 보았을 때 이해가 가더군요...
e는 true, false 로 1, 0을 번갈아 간다.
왼쪽 자릿수부터 0부터 9까지 비교하면서 소수인 것들만 집어 넣는 형식이었네요

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그럼요 :)
전기통닭구이라는 표현이 더 재밌는 것 같은데요 ㅋㅋㅋ

Copy link
Collaborator

@seongwon030 seongwon030 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

처음에 풀었던 게 시간복잡도가 말도안되게 나와서 풀이를 좀 참고 했네요.

일단 해당 숫자를 문자열로 변환한게 N자리수면 반환하고

아닐 때에도 홀수인 경우에만 dfs를 실행하도록 2만큼의 간격으로 반복문을 진행했습니다.

def dfs(x):
    if len(str(x)) == n:
        answer.append(x)
        return
    for i in range(1, 10, 2):
        if isprime(x*10+i):
            dfs(x*10+i)

좋은 문제 잘 보고 갑니다!

@yuyu0830 yuyu0830 merged commit b5a0e72 into main Sep 2, 2024
@yuyu0830 yuyu0830 deleted the 25-yuyu0830 branch September 2, 2024 07:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants