DY N DY

BOJ 1963 소수 경로(C++) 본문

PARK/ALGORITHM

BOJ 1963 소수 경로(C++)

손세지 2016. 9. 9. 10:55


시간 제한메모리 제한제출정답맞은 사람정답 비율
2 초128 MB156479154953.249%

문제

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

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

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

입력

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

출력

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

예제 입력 

3
1033 8179
1373 8017
1033 1033

예제 출력 

6
7
0

힌트

출처

ACM-ICPC Regionals Europe Northwestern European Regional Contest NWERC 2006 G번

  • 문제의 오타를 찾은 사람: waylight3

알고리즘 분류




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
#include    <cstdio>
#include    <cmath>
#pragma warning(disable:4996)
 
int P[11111];
int visit[11111];
int queue[9999];
int rear, front;
int main()
{
 
    for (int i = 2; i <= 100++i)
    if (P[i] == 0)
    for (int j = i*i; j <= 10000; j += i)
        P[j] = 1;
 
 
    int TC;
    int S, E;
    scanf("%d"&TC);
    for (int t = 1; t <= TC; ++t)
    {
        int res = -1;
        scanf("%d%d"&S, &E);
        for (int i = 1000; i <= 9999++i) //초기화
            visit[i] = -1;
 
        front = rear = 1;
        queue[rear++= S;
        visit[S] = 0;
 
        while (front < rear)
        {
            int num = queue[front++];
            if (num == E)
                break;
 
            int n1, n2, n3, n4;
            n1 = num / 1000 * 1000; n2 = num % 1000 / 100 * 100; n3 = num % 100 / 10 * 10; n4 = num % 10;
            for (int i = 0; i <= 9++i)
            {
                if (visit[n1 + n2 + n3 + i] == -1 && P[n1 + n2 + n3 + i] == 0)
                {
                    queue[rear++= n1 + n2 + n3 + i;
                    visit[n1 + n2 + n3 + i] = visit[num] + 1;
                }
                if (visit[n1 + n2 + i * 10 + n4] == -1 && P[n1 + n2 + i * 10 + n4] == 0)
                {
                    queue[rear++= n1 + n2 + i * 10 + n4;
                    visit[n1 + n2 + i * 10 + n4] = visit[num] + 1;
                }
                if (visit[n1 + i * 100 + n3 + n4] == -1 && P[n1 + i * 100 + n3 + n4] == 0)
                {
                    queue[rear++= n1 + i * 100 + n3 + n4;
                    visit[n1 + i * 100 + n3 + n4] = visit[num] + 1;
                }
                if (i == 0)
                    continue;
                if (visit[i * 1000 + n2 + n3 + n4] == -1 && P[i * 1000 + n2 + n3 + n4] == 0)
                {
                    queue[rear++= i * 1000 + n2 + n3 + n4;
                    visit[i * 1000 + n2 + n3 + n4] = visit[num] + 1;
                }
            }
        }
 
        if (visit[E] == -1)
            printf("Impossible\n");
        else
            printf("%d\n", visit[E]);
    }
 
    return 0;
}
cs

전형적인 BFS문제였다. 

장기엘레베이터 같은 문제였지만 소수구하기가 포함되어있어 약간 더 풀기에 재미있었던(?) 문제였다. 


우선 소수를 구한다. 소수를 구하는 공식은 에라토스테네스의 체라는 유명한 방법이 있으므로 넘어간다. 


4자리 수 이므로 1000~9999사이의 수이다. 

4개로 나누어 주었다. 1000의 자리, 100의 자리, 10의 자리, 1의 자리. 

이것을 0~9까지 돌면서 소수이고 방문하지 않은 수를 queue에 넣어주며 visit에 몇번 변환해야 바뀔 수 있는지 넣어주었다. 

(방문과 동시에 횟수까지 처리하기 위함)


주의해야 할 점은 1000의 자리는 0이 되면 안되기 때문에 57~8라인에서 i가 0인 경우 아래쪽은 실행하지 않았다는 것이다. 

그외에는 어렵지 않았다.

'PARK > ALGORITHM' 카테고리의 다른 글

실력키우기 오목(C++)  (0) 2016.09.19
실력키우기 주사위 쌓기(C++)  (0) 2016.09.19
알고리즘 & BOJ 2302 극장좌석(C++)  (0) 2016.09.08
실력키우기 색종이(초)(C++)  (0) 2016.09.08
BOJ 2240 자두나무(C++)  (0) 2016.09.07