포스트

[C++] 백준 16434번: 드래곤 앤 던전

문제

난이도 : 골드 4
백준 16434번 : 드래곤 앤 던전

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include <bits/stdc++.h>

typedef long long ll;
using namespace std;

ll N, atk;

struct Room
{
    int t, a, h;
};

vector<Room> v;

bool Check(ll maxHP)
{
    ll curHP = maxHP;
    ll curAtk = atk;

    for (int i = 0; i < N; i++)
    {
        int t = v[i].t;
        int a = v[i].a;
        int h = v[i].h;

        if (t == 1)
        {
            ll n = ceil((double)h / curAtk);

            if (curHP - a * (n - 1) <= 0) return false;
            curHP -= a * (n - 1);
        }
        else if (t == 2)
        {
            curHP = min(maxHP, curHP + h);
            curAtk += a;
        }
    }

    return true;
}
int main()
{
    cin >> N >> atk;

    for (int i = 0; i < N; i++)
    {
        Room room;
        cin >> room.t >> room.a >> room.h;
        
        v.push_back(room);
    }

    ll low = 0; ll high = LLONG_MAX;
    ll ret = LLONG_MAX;

    while (low <= high)
    {
        ll mid = (low + high) / 2;

        if (Check(mid))
        {
            high = mid - 1;
            ret = mid;
        }
        else
        {
            low = mid + 1;
        }
    }
    
    cout << ret << '\n';

    return 0;
}

풀이

이전까지의 이분 탐색 문제와 비슷하게 용사의 최대 피를 이분 탐색을 통해 최솟값을 찾는 문제이다.
Room 구조체를 만들어 방의 정보를 입력받고 벡터에 저장한다.
low와 high를 선언해 이 변수들로 이분 탐색을 할 것인데 이 때 변수의 범위를 잘 모르겠다면 사용하는 변수 타입의 MAX 값을 쓴다. 그런데 문제의 예제 2번에 보면 정답이 1000억이 넘는다. 이 말은? INT형을 못쓴다는 점. 그래서 나는 long long 타입으로 최솟값, 최댓값을 정했다.
이제 mid를 구해가며 Check 함수를 보자.
Check 함수의 처음엔 함수에서 쓸 현재 체력을 최대 체력으로 초기화하고 현재 공격력을 초깃값으로 초기화한다.
그리고 반복문을 통해 방을 돌아다니며 자기만의 로직을 구현하면 되는데 이 때 몬스터가 있는 방일때를 조심해야한다.
처음에 아무 생각 없이 while문으로 몬스터의 h가 0 이하일 때 까지로 했는데 그냥 틀렸다고 나와서 이거를 최적화 해줘야 한다.
용사가 몬스터를 잡을 수 있는 횟수는 바로 (몬스터의 피) / (용사의 공격력)인데 이게 0으로 떨어지면 잡는건데 0으로 안떨어지면 1번 더 공격해야 잡는거니까 통일성을 위해 ceil 함수로 올림 처리를 해주었다(이때 double형으로 타입변환 해줌)
그래서 구한 n번을 이용해 용사가 n번 때릴 때 몬스터는 용사를 n - 1번 때릴 수 있다. 왜냐면 용사가 먼저 공격이니까 먼저 공격해서 죽으면 몬스터는 공격을 못함
몬스터가 a라는 공격력으로 n - 1 번을 때렸을 때 만약 용사가 죽는다면? 바로 false를 리턴해 용사의 최대 체력을 올리는 로직을 실행함.
포션 방일때는 min(최대체력, 현재체력+포션)으로 min 값을 현재 체력에 덮어쓴다.
그리고 무사히 반복문을 빠져나가면 true를 리턴한다.

true를 리턴했으면 현재 구한 최대체력으로 던전이 돌아지는거니까 이거보다 더 작은 최대 체력으로도 돌아지는지 확인하면서 구하면 끝

결과

image

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.