본문 바로가기

공부/알고리즘 문제풀이

[알고스팟] 두니발 박사의 탈옥

반응형

문제 링크


문제 정보

문제

위험한 살인마 두니발 박사가 감옥에서 탈출했습니다. 수배지를 붙이고 군경이 24시간 그를 추적하고 있지만 용의주도한 두니발 박사는 쉽사리 잡히지 않았습니다. d일이 지난 후에야 경찰은 프로그래밍의 천재인 찰리 교수)를 찾아왔습니다. 찰리 교수는 두니발 박사가 감옥에 남겨둔 노트를 분석해 다음과 같은 가설을 세웠습니다.

  • 두니발 박사는 검문을 피해 산길로만 이동한다.
  • 두니발 박사는 교도소를 탈출한 당일, 교도소와 인접한 마을 하나로 도망쳐 은신한다.
  • 두니발 박사는 수색을 피하기 위해 그 후 매일 인접한 마을로 움직여 은신한다.

dunibal.png

이 가설을 검증하기 위해 교도소로부터 산길로 연결된 n 개 마을들의 지도를 위 그림과 같이 구했습니다. 두니발 박사가 이 가설에 맞춰 행동하고, 움직일 수 있는 마을이 여러 개 있을 경우 그 중의 하나를 임의로 선택한다고 합시다. d 일 후에 두니발 교수가 각 마을에 있을 확률을 계산하는 프로그램을 작성하세요.

예를 들어 위 지도에서 3번 마을에 교도소가 있다고 합시다. 탈옥 직후 두니발 교수는 0번, 1번, 2번, 4번, 5번 중의 한 도시를 임의로 골라 도망칩니다. 따라서 1일 후에 두니발 교수가 0번 마을에 숨어 있을 확률은 1/5이고, 2일 후에 1번 마을에 숨어 있을 확률은 1/15입니다.

입력

입력의 첫 줄에는 테스트 케이스의 수 c (1 <= c <= 50) 가 주어집니다. 그 후 각 줄에 지도에 포함된 마을의 수 n (2 <= n <= 50) 과 탈출 후 지금까지 지난 일수 d (1 <= d <= 100), 그리고 교도소가 있는 마을의 번호 p (0 <= p < n) 가 주어집니다. 마을은 0번부터 n-1 번까지 순서대로 번호가 매겨져 있습니다. 그 후 n 줄에는 각각 n 개의 정수로 행렬 A 가 주어집니다. i 번 행의 j 번 숫자 A[i][j] 가 1인 경우 i 번 마을에서 j 번 마을을 잇는 산길이 있다는 것을 의미하며, 0인 경우 길이 없다는 것을 의미합니다. 그 다음 줄에 확률을 계산할 마을의 수 t (1 <= t <= n) 가 주어지고, 그 다음 줄에 t 개의 정수로 확률을 계산할 마을의 번호 q (0 <= q < n) 가 주어집니다.

한 마을에서 다른 마을로 길이 있으면 반대 방향으로도 항상 있으며, 한 마을에서 자기 자신으로 연결되는 길은 없다고 가정해도 좋습니다.

출력

각 테스트 케이스마다 t 개의 실수로 각 마을에 두니발 박사가 숨어 있을 확률을 출력합니다. 10-7 이하의 절대/상대 오차가 있는 경우 정답으로 처리됩니다.

예제 입력

2
5 2 0
0 1 1 1 0
1 0 0 0 1
1 0 0 0 0
1 0 0 0 0
0 1 0 0 0
3
0 2 4
8 2 3
0 1 1 1 0 0 0 0
1 0 0 1 0 0 0 0
1 0 0 1 0 0 0 0
1 1 1 0 1 1 0 0
0 0 0 1 0 0 1 1
0 0 0 1 0 0 0 1
0 0 0 0 1 0 0 0
0 0 0 0 1 1 0 0
4
3 1 2 6

예제 출력

0.83333333 0.00000000 0.16666667
0.43333333 0.06666667 0.06666667 0.06666667


어떻게 풀까?


문제를 살펴봅시다! 

days일에 a 마을에 있을 확률을 라고 하고, a 마을에서 b 마을로 이동할 확률을라고 한다면,

 


임을 알 수 있습니다.


따라서, 위 식을 이용해서 P[days][n]의 배열을 만들고,

시작 마을이 p이기 때문에

P[0][p]을 1로 초기화 한 다음에 day와 마을 수 n만큼 반복해주면 간단하게 답을 구할 수 있습니다!


코드


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
#pragma once
#include<cstdio>
#include<cstring>
 
int adj[50][50]; int n, p;
int deg[50];
double adj2[50][50];
double memoi[101][50];
 
double dp[101][50];
 
int main()
{
    int c;
 
    scanf("%d\n"&c);
 
    while (c--)
    {
        int d;
 
        scanf("%d %d %d\n"&n, &d, &p);
 
        memset(deg, 0sizeof(deg));
 
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n; j++)
            {
                scanf("%d \n"&adj[i][j]);
                deg[i] += adj[i][j];
            }
        }
 
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n; j++)
            {
                adj2[i][j] = (double)adj[i][j] / deg[i];
            }
        }
 
        memset(dp, 0sizeof(dp));
 
        dp[0][p] = 1;
 
        for (int days = 0; days < d; days++)
        {
            for (int i = 0; i < n; i++)
            {
                if (dp[days][i] != 0)
                {
                    for (int j = 0; j < n; j++)
                    {
                        dp[days + 1][j] += dp[days][i] * adj2[i][j];
                    }
                }
            }
        }
 
        int t;
        scanf("%d\n"&t);
 
        while(t--)
        {
            int q;
            scanf("%d \n"&q);
 
            printf("%.10lf ", dp[d][q]);
        }
 
        printf("\n");
    }
    return 0;
}
cs

여담

오늘도.. deg 배열을 초기화 하지 않아서 정답을 제대로 맞추지 못했었습니다.
초기화 하는 부분을 찾는데 꽤 많은 시간을 소모했습니다.
항상 초기화 잘하고, 문제를 잘 읽는 것을 잊지 맙시다!


그리고 유효 숫자가 소숫점 7 자리 까지라고 나와있습니다.

보통 float는 유효 숫자가 6~7 자리까지이기 때문에, 이처럼 유효 자리 숫자가 있는 경우에는 double을 사용하여 풀도록 합시다! 

나중에 이러한 소소한 팁도 올리겠습니다!

반응형