본문 바로가기
Programing/프로그래머스 오답노트

[프로그래머스] 피로도 - ( 순열 permutations, 재귀 )

by yooom 2023. 9. 29.
문제 설명
XX게임에는 피로도 시스템(0 이상의 정수로 표현합니다)이 있으며, 일정 피로도를 사용해서 던전을 탐험할 수 있습니다. 이때, 각 던전마다 탐험을 시작하기 위해 필요한 "최소 필요 피로도"와 던전 탐험을 마쳤을 때 소모되는 "소모 피로도"가 있습니다. "최소 필요 피로도"는 해당 던전을 탐험하기 위해 가지고 있어야 하는 최소한의 피로도를 나타내며, "소모 피로도"는 던전을 탐험한 후 소모되는 피로도를 나타냅니다. 예를 들어 "최소 필요 피로도"가 80, "소모 피로도"가 20인 던전을 탐험하기 위해서는 유저의 현재 남은 피로도는 80 이상 이어야 하며, 던전을 탐험한 후에는 피로도 20이 소모됩니다. 이 게임에는 하루에 한 번씩 탐험할 수 있는 던전이 여러개 있는데, 한 유저가 오늘 이 던전들을 최대한 많이 탐험하려 합니다. 유저의 현재 피로도 k와 각 던전별 "최소 필요 피로도", "소모 피로도"가 담긴 2차원 배열 dungeons 가 매개변수로 주어질 때, 유저가 탐험할수 있는 최대 던전 수를 return 하도록 solution 함수를 완성해주세요.
k는 1 이상 5,000 이하인 자연수입니다. dungeons의 세로(행) 길이(즉, 던전의 개수)는 1 이상 8 이하입니다. dungeons의 가로(열) 길이는 2 입니다. dungeons의 각 행은 각 던전의 ["최소 필요 피로도", "소모 피로도"] 입니다. "최소 필요 피로도"는 항상 "소모 피로도"보다 크거나 같습니다. "최소 필요 피로도"와 "소모 피로도"는 1 이상 1,000 이하인 자연수입니다. 서로 다른 던전의 ["최소 필요 피로도", "소모 피로도"]가 서로 같을 수 있습니다.

 

풀이

던전이 8개라면, 던전을 탐색하는 경우의 수는 8! 이다. 8중 for 구문을 만들거나, 순열에 관련된 함수를 사용해야한다.

전체 탐색을 하는 것이 내가 생각할 수 있는 최선의 방법인 것 같다.

from itertools import permutations # 순열 함수를 이용한다.

def goin(k, arr): # 피로도와 2차원 배열인 던전 순서를 받는다.
    cnt = 0
    for i in arr:
        if k>=i[0]: # 피로도가 허용치이면 연산을 한다.
            k-=i[1]
            cnt+=1
    return cnt  # 방문한 던전을 센다

def solution(k, dungeons):
    arr = list(permutations(dungeons)) # 순열로 찾아낸 모든 배열을 구한다
    cnt = []
    for i in arr:
        cnt.append(goin(k, i))
        
    return max(arr1) # 방문한 던전의 초댓값을 찾는다.

전체 탐색 말고 다른 방법을 찾아보려고 이틀을 고민했는데, 막상 최후의 방법이라는 생각으로 전체 탐색을 시도하니 5분도 안되어 코드를 짜고 통과해버렸다.

평소에 연습할 때, 수학적으로 간단하게 표현할 수 있는 상황을 기억해두고 그 외의 상황에는 전체 탐색을 과감히 시도해야할 것 같다.

 

재귀 함수로 푼 다른 사람의 풀이를 보자. 이 풀이는 깊이 우선 탐색(DFS)로 접근했다.

answer = 0

def dfs(k, cnt, dungeons):
    global answer
    if cnt > answer:
        answer = cnt

    for j in range(N):
        if k >= dungeons[j][0] and not visited[j]: # j는 0,1,2가 반복하지만, 재귀함수로 여러 층 반복
            visited[j] = 1
            dfs(k - dungeons[j][1], cnt + 1, dungeons) # 재귀
            visited[j] = 0

def solution(k, dungeons):
    global N, visited
    N = len(dungeons)  # 던전 개수만큼 반복한다.
    visited = [0] * N  # 들리지 않은 던전은 0으로 표현
    dfs(k, 0, dungeons) # 재귀
    return answer

dungeons[ j ] 의 j가 0,1,2 를 반복할 때, 재귀 함수에서도 j 는 0,1,2를 반복하며, 실제로는 던전이 3개( N=3 )이므로 3층 구조이다.

하지만, 재귀함수가 어떻게 실행되고 어떻게 빠져나오는지 시각화가 잘 되지 않았다. Python Tutor를 참고하여 재귀함수 구동 순서를 익혔다.

 

 

↓ Python Tutor 를 이용해서 메모리가 할당되고 캐쉬가 생기고 사라지는 것을 시각화하여 볼 수 있다.

https://pythontutor.com/visualize.html#mode=edit

 

Python Tutor code visualizer: Visualize code in Python, JavaScript, C, C++, and Java

Please wait ... your code is running (up to 10 seconds) Write code in Python 3.11 [newest version, latest features not tested yet!] Python 3.6 [reliable stable version, select 3.11 for newest] C (C17 + GNU extensions, gcc 9.3) C++ (C++20 + GNU extensions,

pythontutor.com

 

 

 

출처

https://school.programmers.co.kr/learn/courses/30/lessons/87946

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

728x90

댓글