99클럽 코테 스터디 22일차 TIL + 완전탐색

gahyunkim·2024년 11월 18일

항해99

목록 보기
22/34
post-thumbnail

프로그래머스 피로도

문제 설명

XX게임에는 피로도 시스템(0 이상의 정수로 표현합니다)이 있으며, 일정 피로도를 사용해서 던전을 탐험할 수 있습니다. 이때, 각 던전마다 탐험을 시작하기 위해 필요한 "최소 필요 피로도"와 던전 탐험을 마쳤을 때 소모되는 "소모 피로도"가 있습니다. "최소 필요 피로도"는 해당 던전을 탐험하기 위해 가지고 있어야 하는 최소한의 피로도를 나타내며, "소모 피로도"는 던전을 탐험한 후 소모되는 피로도를 나타냅니다. 예를 들어 "최소 필요 피로도"가 80, "소모 피로도"가 20인 던전을 탐험하기 위해서는 유저의 현재 남은 피로도는 80 이상 이어야 하며, 던전을 탐험한 후에는 피로도 20이 소모됩니다.

이 게임에는 하루에 한 번씩 탐험할 수 있는 던전이 여러개 있는데, 한 유저가 오늘 이 던전들을 최대한 많이 탐험하려 합니다. 유저의 현재 피로도 k와 각 던전별 "최소 필요 피로도", "소모 피로도"가 담긴 2차원 배열 dungeons 가 매개변수로 주어질 때, 유저가 탐험할수 있는 최대 던전 수를 return 하도록 solution 함수를 완성해주세요.

[제한사항]

  • k는 1 이상 5,000 이하인 자연수입니다.
  • dungeons의 세로(행) 길이(즉, 던전의 개수)는 1 이상 8 이하입니다.
    • dungeons의 가로(열) 길이는 2 입니다.
    • dungeons의 각 행은 각 던전의 ["최소 필요 피로도", "소모 피로도"] 입니다.
    • "최소 필요 피로도"는 항상 "소모 피로도"보다 크거나 같습니다.
    • "최소 필요 피로도"와 "소모 피로도"는 1 이상 1,000 이하인 자연수입니다.
    • 서로 다른 던전의 ["최소 필요 피로도", "소모 피로도"]가 서로 같을 수 있습니다.

[입출력 예]

kdungeonsresult
80[[80,20],[50,40],[30,10]]3

문제 해석하기

  • 하루 한 번씩 탐험할 수 있는 던전이 여러개 ⇒ 한 유저가 오늘 이 던전들을 최대한 많이 탐색하려함
  • 최대한 많이 탐색하려면, dungeons에서 람다함수를 이용해서 최소 필요도가 큰것부터 내림차순으로 정렬해야 한다.
    • cnt를 사용하여, result를 구하도록 한다.
    • [처음 탐색하는 던전이 0번째 인 경우] 최소 필요도부터 내림차순으로 정렬 후, 처음 탐색하는 던전에서 (최소 필요도 - 소모피로도) 를 했을때, 다음 탐색하고자 하는 던전의 최소 필요도보다 작은지 아닌지로 판단하여 cnt를 계산하도록 한다.
    • [처음 탐색하는 던전이 1이상의 번째인 경우] 위의 경우처럼 ‘(최소 필요도 - 소모피로도)가 다음 던전의 최소 필요도보다 작다면’ ⇒ 하나의 던전밖에 탐색하지 못하기 때문에, 다음 던전으로 넘어가서 계속 완전 탐색을 할 수 있도록 한다.
  • 결국 우리가 기준으로 해야하는것은 내림차순으로 정렬된 dungeons의 최소 필요 피로도이고, (최소 필요피로도 - 소모 피로도) 가 다음 던전의 최소 피로도 보다 큰지작은지 여부를 확인하는 것이 중요하다.
  • 던전 탐험에서 최대한 많은 던전을 탐험하려면, 모든 탐험 순서를 고려하는 완전 탐색이 필요하다. 이를 위해 순열 생성 방식이나 DFS를 활용할 수 있으며, 각 방식은 문제의 제약(던전 최대 8개) 내에서 최적의 순서를 탐색하는 데 적합하다. 정렬만으로 문제를 해결하려는 접근은 제한적이므로 완전 탐색을 기반으로 구현해야 한다

  1. 순열을 이용한 완정 탐색
  • 모든 던전 순서를 생성하고, 각 순서에 대해 탐섬 가능한 던전 수를 계산한다

2.. DFS를 활용한 완전 탐색(백트래킹)

  • 백트래킹을 사용해서 불필요한 탐색을 줄인다.
  • 상태를 저장해서 재귀적으로 탐색하기 때문에 효율적인 탐색이 가능하다
from itertools import permutations

def solution(k, dungeons):
    max_count = 0  # 탐험 가능한 최대 던전 수

    # 모든 탐험 순서를 확인
    for order in permutations(dungeons):
        current_k = k  # 현재 피로도
        count = 0      # 현재 탐험한 던전 수
        
        # 현재 순서로 던전 탐험
        for dungeon in order:
            min_required, fatigue = dungeon
            if current_k >= min_required:  # 최소 필요 피로도를 충족하는 경우
                current_k -= fatigue       # 피로도 소모
                count += 1                # 탐험 던전 수 증가
            else:
                break  # 더 이상 탐험 불가, 다음 순열로 이동

        # 최대 탐험 수 갱신
        max_count = max(max_count, count)

    return max_count

---------------------------------------------------------------------------------

def solution(k, dungeons):
    max_count = 0  # 최대 탐험 가능한 던전 수
    
    def dfs(k, visited, count):
        nonlocal max_count
        max_count = max(max_count, count)  # 최대 탐험 수 갱신
        
        for i in range(len(dungeons)):
            if not visited[i]:  # 아직 탐험하지 않은 던전이라면
                min_required, fatigue = dungeons[i]
                if k >= min_required:  # 최소 필요 피로도를 만족하는 경우
                    visited[i] = True  # 탐험 처리
                    dfs(k - fatigue, visited, count + 1)  # 다음 탐험
                    visited[i] = False  # 백트래킹

    # 초기 상태: 모든 던전을 방문하지 않음
    visited = [False] * len(dungeons)
    dfs(k, visited, 0)
    
    return max_count

오늘의 회고

두가지 방식으로 문제를 풀어보면서, 더 나은 방식으로 해결할 수 있어서 좋았다. DFS를 이용해서 시간을 더 줄여볼수도 있었고, permutation을 이용해서 순열을 이용해서 문제를 풀어볼 수도 있었다.

새로운 방식으로 문제를 풀어보면서 더 나은 해결방안을 찾을 수 있어서 좋은 경험이었다.

0개의 댓글