문제링크 입니다

[NUMB3RS] 문제 😭😭😭😭😭

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

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

이 가설을 검증하기 위해 교도소로부터 산길로 연결된 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

전체 코드는 다음과 같습니다.

//
//  NUMB3RS.cpp
//  AALGGO
//
//  Created by inhyeok on 2021/09/29.
//

#include <iostream>
#include <fstream>
#include <cstring>
using namespace std;

ifstream fin("NUMB3RS.txt");

int n=0; // 마을의 수
int d=0; // 지난 일수
int p=0; // 교도소가 있는 마을의 번호
int q=0; // 계산할 마을의 번호
double cache[51][101]; // 메모이제이션을 위해
int A[51][51];
int deg[51];

/*
마을과 인접해 있는 마을의 수를 계산하여 deg에 저장.
 */
void Calculate_deg(int n){
    for(int i=0; i<n; i++){
        for(int j=0; j<n; j++){
            if(A[i][j])
                deg[i]++;
        }
    }
}
/*
역으로 생각해보자 -> d일 후 q마을 부터 시작.
here -> 현재 위치
days -> 지난 일 수.
 */
double dunibal(int here, int days){
    // 기저 사례
    if(days==0) return (here== p ? 1.0 : 0.0);
    double &ret = cache[here][days];
    if(ret > -0.5) return ret;
    ret = 0.0;
    for(int there = 0; there < n; there++){
        if(A[here][there])
            ret += dunibal(there, days-1) / deg[there];
    }
    return ret;
}

int main(int argc, const char * argv[]) {
    int Test_case;
    fin >> Test_case;
    for (int i=0; i < Test_case ; i++){
        fin >> n;
        fin >> d;
        fin >> p;
        memset(cache,-1,sizeof(cache));
        memset(deg,0,sizeof(deg));
        memset(A,0,sizeof(A));
        for(int j =0; j< n; j++){
            for(int k=0; k<n; k++){
                fin >> A[j][k];
            }
        }
        Calculate_deg(n);
        int t=0; // 확률을 계산할 마을 번호의 수
        fin >> t;
        for(int j=0; j<t; j++){
            fin >> q;
            printf("%.8f ", dunibal(q,d));
        }
        cout << endl;
    }
    return 0;
}

Comments