본문 바로가기

백준/그래프

백준 16681 - 등산

728x90
728x90

https://www.acmicpc.net/problem/16681

힌트

더보기

집 -> 어떤 지점 방향으로는 올라가고 어떤 지점 -> 고려대학교 방향으로는 내려간다...

 

여기서 어떤 아이디어를 떠올릴 수 있겠는가?

풀이

더보기

어떤 지점 $X$를 기준으로 내려가야 되는 경로와 올라가는 경로가 다르다.

 

이를 살펴보면 $X$에서 고려대학교까지 내려가는 것은 고려대학교에서 $X$까지 올라가는 것과 같다.

 

따라서 다음과 같은 아이디어를 생각할 수 있다.

 

1. 집에서 올라가는 최단 경로 $sp_{1, x}$들을 계산한다.

2. 고려대학교에서 올라가는 최단 경로 $sp_{2, x}$들을 계산한다.

3. 어떤 지점 i에서 $sp_{1, i}$ 와 $sp_{2, i}$가 존재하면 i를 기준으로 문제 조건에 맞는 등산이 가능하고 최대 성취감을 계산할 수 있다.

 

따라서 두 최단 경로 집합을 구하기 위해 dist 배열을 두 개 만들어 시작이 1(집)과 n(고려대학교)일 때의 최단 경로를 각각 계산하고 각 정점마다 통행이 가능하면(cost가 INF 값이 아니면) 얻을 수 있는 성취감의 최댓값을 구하면 된다.

 

다익스트라 알고리즘으로 최단 경로를 구할 때 현재 지점에서 높은 지점으로만 갈 수 있다는 사실에 유의하도록 한다.

 

오버플로우를 조심하며 문제에서 요구한 답을 찾도록 하자.

 

전체 코드

#pragma GCC target("sse,sse2,sse3,ssse3,sse4,avx,avx2,fma")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")

#include "bits/stdc++.h"
#include "ext/rope"

using namespace std;
using namespace __gnu_cxx;

using pii = pair<int, int>;
using ll = long long;

#define no "Impossible"
int n, m, d, e;
vector<pii> g[100001];
int h[100001];
array<ll, 100001> dp1, dp2;

void dijkstra(int stt, array<ll, 100001> &ar)
{
    fill(ar.begin(), ar.end(), 1e18);
    using pli = pair<ll, int>;
    priority_queue<pli, vector<pli>, greater<>> pq;

    pq.push({0, stt});
    ar[stt] = 0;

    while (pq.size())
    {
        ll val;
        int node;
        tie(val, node) = pq.top();
        pq.pop();

        if (ar[node] < val) continue;

        for (auto [nnode, fee]: g[node])
        {
            ll nval = fee + val;

            if (nnode == stt || nnode == n) continue;
            if (h[nnode] <= h[node]) continue;
            if (nval >= ar[nnode]) continue;

            ar[nnode] = nval;
            pq.push({nval, nnode});
        }
    }
}

void solve()
{
    cin >> n >> m >> d >> e;

    for (int i = 1; i <= n; i++)
    {
        cin >> h[i];
    }

    for (int i = 0; i < m; i++)
    {
        int go, to, fee;
        cin >> go >> to >> fee;
        g[go].emplace_back(to, fee);
        g[to].emplace_back(go, fee);
    }

    dijkstra(1, dp1);
    dijkstra(n, dp2);

    ll ans = -1e18;

    for (int i = 2; i < n; i++)
    {
        if (dp1[i] == 1e18 || dp2[i] == 1e18) continue;
        ans = max(ans, (ll)h[i] * e - dp1[i] * d - dp2[i] * d);
    }

    if (ans == -1e18) cout << no;
    else cout << ans;
}

int main()
{
    cin.tie(nullptr);
    ios::sync_with_stdio(false);

    solve();
}

제출 기록

실수로 long long 처리를 제대로 하지 않아 몇 번 틀렸다.

 

728x90
728x90

'백준 > 그래프' 카테고리의 다른 글

백준 2224 - 명제 증명  (0) 2022.05.13
백준 1525 - 퍼즐  (0) 2021.11.04
백준 1325 - 효율적인 해킹  (0) 2021.10.27
[COCI] 백준 3055 - 탈출  (0) 2021.10.26
[KOI] 백준 2583 - 영역 구하기  (0) 2021.10.25