프로그래머스 - 피로도

Computer Science/Problem Solving

문제설명

 

제한사항 및 입출력

풀이

문제의 제한사항을 확인해보면

1 <= k <= 5000

1 <= 던전의 개수 <= 8

으로 제한되어있다. 따라서 모든 던전의 순서를 확인해도 8!이기 때문에 굉장히 작은 것을 알 수 있다. 

그러므로 간단하게 permutations을 활용하여 모든 경우의 수를 확인하고 가장 큰 값을 리턴하는 완전탐색으로 구현했다.

 

내 코드

가지 못하는 곳은 break를 해주면서 빠르게 제외시켜주었다. 실제로는 던전의 개수가 8개일 때 8!에 던전의 개수만큼 한 번 더 반복하기 때문에 8! * 8인 것을 확인할 수 있다. 약 32만이라는 작은 숫자이므로 간단하게 통과할 수 있었다.

 

고찰

내가 생각한 코드의 시간복잡도는 O(n * n!)로 매우 크다.

던전의 개수가 12개만 넘는다고 해도 5억에 가까운 숫자이므로 완전탐색은 힘들 수 있다.

 

1. 정렬을 활용한 그리디

사실 제일 처음 생각난 방법은 아니라 정렬한 후 "그리디하게 풀 수 있지 않을까?" 라는 생각이었다. 

하지만 던전을 소모 피로도, 요구 피로도 어떤 걸 기준으로 정렬해도 최적을 보장하기 힘들다는 생각에 완전탐색으로 풀이하게 되었다.

 

2. 백트래킹 + 가지치기

완전탐색을 구현함에 있어서 permutations이 직관적으로 구현하기 쉬워서 permutations을 활용한 코드로 작성했는데, 이번엔 백트래킹을 활용하여 풀이해보았다.

리스트를 활용하여 현재 상태를 복구하고 upper_bound 함수로 가지치기 했다.

 

 

upper_bound(k)는 “비용을 0이라고 가정하고, 지금 k로 요구치(req)만 충족하는 남은 던전 수”를 센다. 비용을 무시하므로 실제보다 많게 잡는다. 가지치기해도 최적해를 보장하기 위해 낙관적으로 잡았다.

가지치기의 핵심 로직은 cnt + upper_bound(k) <= best면, 이 분기에서 최대한 잘해도 현재 최고(best)를 넘을 수 없으니 탐색 중단하는 것이다.

시간복잡도는 똑같이 O(n * n!)이지만 가지치기로 인해 평균적인 통과 시간이 크게 줄었다. 근데 테스트케이스 8번에서는 오히려 늘었다...? 아마 최악의 경우 함수 호출로 인한 오버헤드가 있는 것 같다.

 

3. DP

 

그 다음은 DP를 활용한 풀이이다. 일반적으론 상태를 저장하기가 껄끄러워 비트마스킹을 사용했다. 언제나 dp의 관건은 dp 테이블을 잘 정의하는 것이다.

나는 다음과 같이 dp를 정의했다.

mask(비트마스크): 지금까지 클리어한 던전의 수

dp[mask]: 그 집합을 어떤 순서로든 클리어하고 남길 수 있는 피로도의 최댓값 (불가능하면 -1)

 

핵심은 지금까지 어떤 던전을 클리어했는가(마스크)를 상태로 두고, 그 상태에서 남아있는 최대 피로도를 저장하는 것이다.

 

첫 번째 for문은 모든 상태를 순회하면서 저장된 가장 큰 값(ans)와 현재 마스크의 비트 개수(클리어한 던전의 수)를 비교하여 큰 값을 갱신한다. -> O(2^n)

두 번째 for문은 방문하지 않은 모든 던전들을 확인한다. -> O(n)

1. if (mask >> i) & 1: → i번째 비트가 1이면 이미 깬 던전이므로 패스.

 

2. 현재 남은 피로도 dp[mask]가 이 던전 요구치 req 이상이면 입장 가능

새 상태 nxt = mask | (1<<i) -> i번째 던전을 추가로 깬다면 새로 남을 피로도 rem = dp[mask] - cost

같은 nxt 상태에 도달하는 여러 경로 중 남은 피로도가 더 큰 rem > dp[nxt]일 때만 갱신한다.

 

시간복잡도는 O(n * 2^n)으로 팩토리얼에 비하면 엄청나게 감소했다.

 

전체적으로 통과시간이 크게 줄었다! 언제쯤 처음부터 이런 풀이를 생각할 수 있게 될까...

'Computer Science > Problem Solving' 카테고리의 다른 글

백준 23326 - 홍익 투어리스트  (0) 2025.08.19
백준 13265 - 색칠하기  (0) 2025.08.18
백준 15973 - 두 박스  (0) 2025.08.18
백준 19622 - 회의실 배정 3  (0) 2025.08.17
백준 9047 - 6174  (0) 2025.08.17
'Computer Science/Problem Solving' 카테고리의 다른 글
  • 백준 13265 - 색칠하기
  • 백준 15973 - 두 박스
  • 백준 19622 - 회의실 배정 3
  • 백준 9047 - 6174
hojoo
hojoo
그냥 개발이 즐거운 사람
  • hojoo
    dev_record
    hojoo
  • 전체
    오늘
    어제
    • 분류 전체보기 (82)
      • Study (0)
        • 모든 개발자를 위한 HTTP 웹 기본 지식 (0)
        • Real MySQL 8.0 (0)
        • 친절한 SQL 튜닝 (0)
        • 도메인 주도 개발 시작하기 (0)
        • 대규모 시스템 설계 기초 (0)
      • Computer Science (66)
        • Problem Solving (30)
        • Data Structure (4)
        • Spring Boot (13)
        • DB (1)
        • Java (4)
        • OS (3)
        • Server (2)
        • Tech (0)
      • Security (16)
        • Reversing (15)
        • Assembly (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    2539
    x64dbg
    프로그래머스
    16946
    Reversing
    n^2 배열 자르기
    Lena tutorial
    Header
    12033
    19622
    bean
    9421
    리버싱
    dreamhack.io
    리버싱 핵심원리
    DP
    Spring boot
    레나 튜토리얼
    HTTP
    백준
    15973
    n+1
    자료구조
    servlet
    21278
    13265
    서버 증설 횟수
    DB
    PE header
    소수상근수
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
hojoo
프로그래머스 - 피로도
상단으로

티스토리툴바