본문 바로가기

UCPC

22358 스키장

으아악.. dp인데 상태 저장해야 하는 문제들 너무 어렵다;; 낯설어;;  친해지기도 힘듬;;

 

이전에 풀었던 https://burningjeong.tistory.com/388 관악산 문제 + 벽 부수기랑 비슷한 느낌이다. 

 

전체 코드는 아래랑 같은데 일단 다시 정리 겸 조각조각 땃땃따 

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <functional>
#include <string>
#include <queue>
#include <deque>
#include <stack>
#include <set>
#include <map>
#include <cmath>
#include <cstring>
#include <bitset>
#include <stdio.h>

#define xx first
#define yy second
#define all(x) (x).begin(), (x).end()

using namespace std;
using i64 = long long int;
using ii = pair<int, int>;
using iis = pair<int, string>;
using ii64 = pair<i64, i64>;
using iii = tuple<int, int, int>;

i64 n, m, k, s, t;

vector<i64> adj[100005];
i64         dp[100005][15]; // 출발 했을 떄의 시간의 최댓값
map<ii64, i64> height;

i64 dfs(i64 curr, i64 k) {
    if (dp[curr][k] != -1)
        return dp[curr][k];
    
    auto& res = dp[curr][k];
    res = -2;
    
    if (curr == t && k == 0)
        return res = 0;
    
    for (int i = 0; i < adj[curr].size(); i++) {
        if (curr < adj[curr][i]) {
            i64 next = dfs(adj[curr][i], k);
            if (next == -2)
                continue;
            res = max(res, next + height[{curr, adj[curr][i]}]);
        }
        else if (k > 0) {
            res = max(res, dfs(adj[curr][i], k - 1));
        }
    }
    
    return res;
}

int main() {
    scanf("%lld %lld %lld %lld %lld", &n, &m, &k, &s, &t);
    
    memset(dp, -1, sizeof(dp));
    for (int i = 0; i < m; i++) {
        i64 x, y, h;
        scanf("%lld %lld %lld", &x, &y, &h);
        
        adj[x].push_back(y);
        adj[y].push_back(x);
        height[{x, y}] = h;
        height[{y, x}] = h;
    }
    
    i64 res = dfs(s, k);
    
    if (res == -2)
        printf("-1");
    else
        printf("%lld", res);
    
    return 0;
}

 

----

분석

 

i64 n, m, k, s, t;

vector<i64> adj[100005];
i64         dp[100005][15]; // 출발 했을 떄의 시간의 최댓값
map<ii64, i64> height;

int main() {
    scanf("%lld %lld %lld %lld %lld", &n, &m, &k, &s, &t);
    
    memset(dp, -1, sizeof(dp));
    for (int i = 0; i < m; i++) {
        i64 x, y, h;
        scanf("%lld %lld %lld", &x, &y, &h);
        
        adj[x].push_back(y);
        adj[y].push_back(x);
        height[{x, y}] = h;
        height[{y, x}] = h;
    }
    
    i64 res = dfs(s, k);
    
    if (res == -2)
        printf("-1");
    else
        printf("%lld", res);
    
    return 0;
}

 

실수로 int로 했다가 틀려서 다 i64로 바꿔서 풀었다. 

기본값으로 dp에 -1로 초기화해줬다. 그리고 인접한 노드 연결하고 간선마다 시간도 저장했다. 

 

그 다음 시작지점에서 dfs 돌린다. 결과로 -2가 나오면 없는 경우이고 나머지면 출력하게 구현했다. 

 

i64 dfs(i64 curr, i64 k) {
    if (dp[curr][k] != -1)
        return dp[curr][k];
    
    auto& res = dp[curr][k];
    res = -2;
    
    if (curr == t && k == 0)
        return res = 0;

이미 값이 계산된 경우 dp에 있는 값을 반환한다. 

 

그게 아니라면 dp에 값을 집어넣어야 하는데 res를 맨 처음 -2로 초기화한다.

 

그 다음 현 위치가 종료 지점이고 k도 0이라면 움직일 수 없으므로 그냥 0을 반환한다. 

종료지점이지만 k가 0이 아니라면 움직일 가능성이 있으므로 다음 단계를 밟는다.

 

    for (int i = 0; i < adj[curr].size(); i++) {
        if (curr < adj[curr][i]) {
            i64 next = dfs(adj[curr][i], k);
            if (next == -2)
                continue;
            res = max(res, next + height[{curr, adj[curr][i]}]);
        }
        else if (k > 0) {
            res = max(res, dfs(adj[curr][i], k - 1));
        }
    }
    
    return res;

그 다음 연결된 노드를 확인한다. 

 

내려가는 노드라면 다음 노드를 기준으로 계산한다.

만약 -2라면 패스하고 그게 아니라면 다음 노드 기준으로 최대 시간 + 다음 노드로 가는 시간을 계산한다. 

 

올라가는 노드라면 k-1을 한 값을 계산하면 된다. 끝~ 어렵다 

'UCPC' 카테고리의 다른 글

22880 봉화대  (0) 2021.08.15
UCPC 2021 본선 후기  (0) 2021.08.14
22353 헤이카카오  (0) 2021.08.01
22351 수학은 체육과목 입니다 3  (0) 2021.08.01
UCPC 2021 예선 후기  (6) 2021.08.01