본문 바로가기
알고리즘/백준

[백준1963] 소수 경로

by RoJae 2019. 4. 23.


정답률이 높았지만, 다른 정답률이 높은 문제들에 비해서 긴 소스코드를 작성해야 하는 문제였습니다.

BFS와 에라토스테네스의 체의 개념을 확실하게 알고 있어야 풀 수 있는 문제입니다.

( BFS로 푸는 이유 => 모든 간선의 비용이 1이다 )

저 같은 경우는, 하나의 큐와 1부터 10000까지 배열을 2개 만들어

queue q는 BFS 접근을 하기 위하여 사용하였고

int visit [10000] 배열은 방문 여부를 확인하는 배열이며, 값은 소수 변환에 필요한 횟수를 가지게 구현하고

bool c [10000] 배열은 소수인지 아닌지 확인하는 배열을 구현하였습니다.



추가적으로는 배열이 아닌 struct { int a, bool b} 혹은  vector<pair<int,bool>> c 컨테이너를 사용하여

충분히 풀 수 있는 문제입니다.


출처 : https://www.acmicpc.net/problem/1963

문제

소수를 유난히도 좋아하는 창영이는 게임 아이디 비밀번호를 4자리 ‘소수’로 정해놓았다. 어느 날 창영이는 친한 친구와 대화를 나누었는데:

  • “이제 슬슬 비번 바꿀 때도 됐잖아”
  • “응 지금은 1033으로 해놨는데... 다음 소수를 무엇으로 할지 고민중이야"
  • “그럼 8179로 해”
  • “흠... 생각 좀 해볼게. 이 게임은 좀 이상해서 비밀번호를 한 번에 한 자리 밖에 못 바꾼단 말이야. 예를 들어 내가 첫 자리만 바꾸면 8033이 되니까 소수가 아니잖아. 여러 단계를 거쳐야 만들 수 있을 것 같은데... 예를 들면... 1033 1733 3733 3739 3779 8779 8179처럼 말이야.”
  • “흠...역시 소수에 미쳤군. 그럼 아예 프로그램을 짜지 그래. 네 자리 소수 두 개를 입력받아서 바꾸는데 몇 단계나 필요한지 계산하게 말야.”
  • “귀찮아”

그렇다. 그래서 여러분이 이 문제를 풀게 되었다. 입력은 항상 네 자리 소수만(1000 이상) 주어진다고 가정하자. 주어진 두 소수 A에서 B로 바꾸는 과정에서도 항상 네 자리 소수임을 유지해야 하고, ‘네 자리 수’라 하였기 때문에 0039 와 같은 1000 미만의 비밀번호는 허용되지 않는다.

입력

첫 줄에 test case의 수 T가 주어진다. 다음 T줄에 걸쳐 각 줄에 1쌍씩 네 자리 소수가 주어진다.

출력

각 test case에 대해 두 소수 사이의 변환에 필요한 최소 회수를 출력한다. 불가능한 경우 Impossible을 출력한다.

예제 입력 1

3
1033 8179
1373 8017
1033 1033

예제 출력 1

6
7
0




소스코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#include<iostream>
#include<queue>
#include<cstring>
 
using namespace std;
 
// 1000부터 9999까지 배열만 사용한다. 
// bool c => 소수이면 false, 소수가 아니면 true이다.
// int visit => 방문했으면 > 0, 방문하지 않았으면 0 이다. 
bool c[10000];
int visit[10000];
queue<int> q;
 
// swap을 사용한 큐 비우기 
void clearQueue(queue<int> &Queue)
{
    queue<int> empty;
    swap(Queue, empty);
}
 
// 소수인지 아닌지 확인하는 메소드 
bool isPrime(int num) {
    if (c[num] == false)
        return true;
    else
        return false;
}
 
// 소수를 저장하기 위해서 사용하는 함수 
void eratos(int beginint end) {
    // 1은 소수이다. 
    c[1= true;
    for (int i = 2; i*<= end; i++) {
        if (c[i] == false) {
            for (int j = i * i; j <= end; j += i) {
                c[j] = true;
            }
        }
    }
}
 
// 숫자 n의 what자리를 to로 바꾼다.
// change_numb(1234,1,3) -> 3234 
int change_numb(int n, int what, int to) {
    int k = n;
    if (what == 1) {
        k -= (n / 1000* 1000;
        k += to * 1000;
    }
    else if (what == 2) {
        k -= ((n / 100) % 10* 100;
        k += to * 100;
    }
    else if (what == 3) {
        k -= ((n % 100/ 10* 10;
        k += to * 10;
    }
    else if (what == 4) {
        k -= n % 10;
        k += to;
    }
    return k;
}
 
// bfs 탐색
void bfs(int from, int to) {
    q.push(from);
    while (!q.empty()) {
        int now = q.front();
        q.pop();
        // 첫번째자리 부터 네번째자리 까지 
        for (int i = 1; i <= 4; i++) { 
            // 해당자리 숫자를 0부터 9까지 바꾸어본다. 
            for (int j = 0; j <= 9; j++) {
                int next = change_numb(now, i, j);
                // next가 소수 && 방문하지 않았고 && 4자리일때 
                if (isPrime(next) && visit[next] == 0 && next >= 1000) {
                    visit[next] = visit[now] + 1;
                    q.push(next);
                    if (next == to) {
                        cout << visit[next]-1 << '\n';        // 시작 위치가 1이기 때문에 -1 연산을 시켜준다. 
                        return;
                    }
                }
            }
        }
    }
    cout << "Impossible" << '\n'
}
 
int main() {
    int t;
    cin >> t;
 
    eratos(110000);                        // 편의상 1부터 10000까지 소수를 구한다.
    
    while (t--) {
        int from, to;
        cin >> from >> to;
        if(from == to)                        // 두 소수가 같은 경우 
            cout << '0' << '\n';
        else{                                // 두 소수가 달라서 연산이 필요한 경우 
            visit[from] = 1;                // 시작 위치 비용 1로 계산 (true) 
            bfs(from, to);
            memset(visit,0,sizeof(visit));    // 방문한 기록 초기화 
            clearQueue(q);                    // 큐 초기화 
        }
    }
    return 0;
}
 
cs



※ 본 글은 개인 포트폴리오 혹은 공부용으로 사용하기 때문에, 무단 복사 유포는 금지하지만, 개인 공부 용도로는 얼마든지 사용하셔도 좋습니다.

'알고리즘 > 백준' 카테고리의 다른 글

[백준 2251] 물통  (0) 2019.04.25
[백준 9019] DSLR  (0) 2019.04.24
[백준 1697] 숨바꼭질  (2) 2019.04.22
[백준 6603] 로또  (0) 2019.04.21

댓글