[프로그래머스 / 완전탐색(L.v2)] 피로도 - 파이썬

Seung Hyeon ·2023년 5월 22일
0

알고리즘

목록 보기
7/10
post-thumbnail

문제 설명

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

제한조건

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

입출력 예시

1. 첫 번째 → 두 번째 → 세 번째 던전 순서로 탐험

  • 현재 피로도: 80
  • 첫 번째 던전을 돌기위해 필요한 "최소 필요 피로도": 80
    → 첫 번째 던전을 탐험 가능
  • 첫 번째 던전의 "소모 피로도"는 20이므로, 던전을 탐험한 후 남은 피로도는 60

  • 남은 피로도: 60
  • 두 번째 던전을 돌기위해 필요한 "최소 필요 피로도": 50
    → 두 번째 던전을 탐험 가능
  • 두 번째 던전의 "소모 피로도"는 40이므로, 던전을 탐험한 후 남은 피로도는 20

  • 남은 피로도: 20
  • 세 번째 던전을 돌기위해 필요한 "최소 필요 피로도": 30
    → 세 번째 던전은 탐험 불가능

 

2. 첫 번째 → 세 번째 → 두 번째 던전 순서로 탐험

  • 현재 피로도: 80
  • 첫 번째 던전을 돌기위해 필요한 "최소 필요 피로도": 80
    → 첫 번째 던전을 탐험 가능
  • 첫 번째 던전의 "소모 피로도"는 20이므로, 던전을 탐험한 후 남은 피로도는 60

  • 남은 피로도: 60
  • 세 번째 던전을 돌기위해 필요한 "최소 필요 피로도": 30
    → 세 번째 던전을 탐험 가능
  • 세 번째 던전의 "소모 피로도"는 10이므로, 던전을 탐험한 후 남은 피로도는 50

  • 남은 피로도: 50
  • 두 번째 던전을 돌기위해 필요한 "최소 필요 피로도": 50
    → 두 번째 던전을 탐험 가능
  • 두 번째 던전의 "소모 피로도"는 40이므로, 던전을 탐험한 후 남은 피로도는 10

따라서 이 경우 세 던전을 모두 탐험할 수 있으며, 유저가 탐험할 수 있는 최대 던전 수는 3입니다.

 

문제 개념 정리

참고 블로그

📌 완전탐색

✔ 모든 경우의 수를 탐색하는 알고리즘

  1. 브루트 포스 : 반복문, 조건문 활용
  2. 순열 : 중복 허용하지 않고 순서대로 늘어 놓은 수
  3. 재귀 호출
  4. 깊이/너비 우선법 (BFS, DFS)

📌순열

itertools 라이브러리

import itertools

a = [1, 2, 3, 4]

permutations_a = list(itertools.permutations(a))
print(permutations_a) # [(1, 2, 3, 4), (1, 2, 4, 3), (1, 3, 2, 4), (1, 3, 4, 2), (1, 4, 2, 3), (1, 4, 3, 2), (2, 1, 3, 4), (2, 1, 4, 3), (2, 3, 1, 4), (2, 3, 4, 1), (2, 4, 1, 3), (2, 4, 3, 1), (3, 1, 2, 4), (3, 1, 4, 2), (3, 2, 1, 4), (3, 2, 4, 1), (3, 4, 1, 2), (3, 4, 2, 1), (4, 1, 2, 3), (4, 1, 3, 2), (4, 2, 1, 3), (4, 2, 3, 1), (4, 3, 1, 2), (4, 3, 2, 1)]

permutations_a = list(itertools.permutations(a, 2))
print(permutations_a) # [(1, 2), (1, 3), (1, 4), (2, 1), (2, 3), (2, 4), (3, 1), (3, 2), (3, 4), (4, 1), (4, 2), (4, 3)]

 

코드

import itertools

def solution(k, dungeons):
    permutation_list = list(itertools.permutations(dungeons))
    
    answer = []   # 모든 경우의 수에 대한 탐험 가능한 던전 개수 모음
    for p in permutation_list: 	
        total = 0   # 탐험 가능 던전 수
        k_copy = k  # k가 바뀐 채로 다음 경우의 수를 탐색하는 것을 방지
        for i, j in p:   # i: 최소 필요 피로도, j: 소모 피로도
        	# print(f'k:{k_copy}, i:{i}, j:{j}')
            if i > k_copy:
                break
            else:
                k_copy = k_copy-j
                total += 1   # 탐험 가능 던전 수 1증가
                
        answer.append(total)

    return max(answer)

코드 설명

permutation_list = list(itertools.permutations(dungeons))

print(permutation_list)

[ ([80, 20], [50, 40], [30, 10]), 
  ([80, 20], [30, 10], [50, 40]), 
  ([50, 40], [80, 20], [30, 10]), 
  ([50, 40], [30, 10], [80, 20]), 
  ([30, 10], [80, 20], [50, 40]), 
  ([30, 10], [50, 40], [80, 20]) ]

if i > k_copy:
    break
else:
    k_copy = k_copy-j
    total += 1
  • i(최소 필요 피로도)가 k(현재 피로도)보다 클 경우, 던전 탐험 불가능
    • 따라서 탐색종료(break) 후, 다음 경우의 수를 탐색하기
  • i(최소 필요 피로도)가 k(현재 피로도)보다 작거나 같을 경우, 던전 탐 가능
    • 따라서 계속해서 해당 경우의 수에 대해 계속 탐색
    • 계속 탐색하는 방법: 현재 피로도 - 소모 피로도 로 다음 던전 탐험

print(answer)
[2, 3, 1, 2, 1, 2]

profile
안되어도 될 때까지

0개의 댓글