백준 알고리즘/Problems

[BOJ/1005] ACM Craft - 풀이 및 코드 (런타임 에러 해결법)

highlaw00 2023. 8. 22. 20:16
 

1005번: ACM Craft

첫째 줄에는 테스트케이스의 개수 T가 주어진다. 각 테스트 케이스는 다음과 같이 주어진다. 첫째 줄에 건물의 개수 N과 건물간의 건설순서 규칙의 총 개수 K이 주어진다. (건물의 번호는 1번부

www.acmicpc.net

문제

풀이

 비슷한 문제인 게임 개발(https://highlaw00-dev.tistory.com/44) 문제를 이미 풀었습니다. 완전탐색의 시간복잡도와 사이클의 유무에 관해 포스팅해두었습니다. 이번 풀이에서는 파이썬의 특징으로 인해 발생하는 런타임 에러에 대해 간략히 다뤄보겠습니다.

 

 재귀적으로 선행 건물의 비용을 구해야하기 때문에 재귀를 여러번 할 가능성이 존재합니다. 백준 채점 서버에서는 파이썬의 최대 재귀 횟수가 1000회로 지정되어 있습니다. 본 문제에서는 최대 재귀 횟수를 증가시켜주지 않으면 런타임 에러(RecursionError)가 발생합니다. 본 문제에서 발생할 수 있는 재귀 함수 호출이 최대 몇번인지 알아보겠습니다.

 

 그래프 탐색 중 DFS 탐색에 대해 알아두고 있으면 최대로 발생할 수 있는 재귀 함수 호출이 몇 번인지 이해하기 쉽습니다. 어떤 건물을 짓기 위해 그 건물이 요구하는 선행 건물의 값을 구하기 위해 재귀하고, 또 그 건물의 요구 선행 건물의 값을 구하기 위해 재귀하고... 이런식으로 재귀를 진행한다고 하면, 건물들의 관계가 다음 그림과 같을 때 재귀 횟수가 가장 크게 됩니다.

 건물의 개수가 1000개 이기 때문에 재귀를 최대 1000번 하게 됩니다. 그런데 왜 인지는 모르겠지만 최대 재귀 호출을 기본값인 1000으로 세팅하면 오류가 발생합니다. 1001로 해주면 런타임 에러가 발생하지 않는데 솔직히 말해서 아직도 왜 이런일이 발생하는지 확인이 되지 않습니다. 코드 상에서 재귀를 1000번 하는 것 같지 않은데 어떤게 문제인지 알고 계신 분께선 댓글 달아주시면 감사하겠습니다!

 

 만약 이런 비슷한 문제에서 N이 1000이상의 값을 가질 수 있게 되면 sys.setrecursionlimit()을 통해 해결하시면 다른 로직상 문제가 없다는 전제하에 통과하실겁니다!

 

코드 

코드 치팅은 BOJ 제재 사유입니다.

더보기

import sys
sys.setrecursionlimit(1001)
input = sys.stdin.readline


# root와 연결된 모든 노드에 대해서 DFS 진행


def get_cost(root):
    requirements_cost = 0
    for v in graph[root]:
        if dp[v] == -1:
            dp[v] = get_cost(v)
        requirements_cost = requirements_cost if requirements_cost > dp[v] else dp[v]
    return requirements_cost + costs[root]


t = int(input().rstrip())
for _ in range(t):
    n, k = map(int, input().rstrip().split())
    costs = [0] + list(map(int, input().rstrip().split()))
    # 건설순서 x, y
    # 그래프를 역순으로 설정
    graph = [[] for _ in range(n+1)]
    for _ in range(k):
        x, y = map(int, input().rstrip().split())
        graph[y].append(x)
    w = int(input().rstrip())
    # dp 테이블 초기화
    # dp[i] = i번째 건물을 짓는데 걸리는 최소 시간
    # dp[i] = max(dp[a1] + dp[a2] + ... dp[aj]) + cost[i] || a1,...,aj는 i를 짓기 위해 반드시 지어야하는 건물
    dp = [0] + [-1 for _ in range(n)]

    ans = get_cost(w)
    print(ans)

참고자료

매우 비슷한 문제인 BOJ 1516 게임 개발 문제도 확인해보세요.

 

[BOJ/1516] 게임 개발 - 풀이 및 코드

1516번: 게임 개발 첫째 줄에 건물의 종류 수 N(1 ≤ N ≤ 500)이 주어진다. 다음 N개의 줄에는 각 건물을 짓는데 걸리는 시간과 그 건물을 짓기 위해 먼저 지어져야 하는 건물들의 번호가 주어진다.

highlaw00-dev.tistory.com