본문 바로가기

백준/그래프

백준 1738 - 골목길

728x90
728x90

icpc.me/1738

문제 분석

가는 길마다 돈을 갈취당하거나 주울 수 있다. 갔던 곳을 또 가도 똑같은 일이 일어난다.

 

최적의 경로는 보유금을 최대로 한 채로 콘도에 도착하는 경우이며

 

최적의 경로에 도달할 수 없는 경우가 있다고 한다. 다음을 생각해볼 수 있다.

 

1. 콘도에 못가는 경우 : 당연하게도 경로 자체가 없으면 콘도에 갈 수 없다.

 

2. 가는 길에 돈을 얻는 사이클이 있는 경우: 민승이는 최대 보유금을 위해 돈을 줍느라 최대 보유금은 양의 무한대로 발산하므로 콘도에 영영 도착할 수 없게 된다.

 

이 내용들을 고려하여 금액을 가중치로 바꾸면 음수의 가중치를 처리할 수 있는 알고리즘이 필요하다. 벨만포드/SPFA로 풀어보자.

구현

콘도에 갈 수 없는 경우를 미리 처리해주자 $n \leq 100$ 이므로 플로이드 워셜을 통해 간단히 콘도까지 갈 수 있는지 여부를 처리해주자.

 

그 후 벨만포드/SPFA를 돌린다. 보유금을 최대로 얻는다는 것에 유의하여 구현하자.

 

완화 과정에서 콘도에 갈 수 없는 간선은 배제해준다.

 

갱신이 시행될 때마다 배열에 최적해를 저장해주자.

 

완화가 n번 이상 진행되거나 콘도로 갈 수 있는 경로가 없으면 -1을 출력, 갈 수 있으면 저장한 최적해를 출력해주자.

 

전체코드 - SPFA로 구현했다.

더보기
#include <bits/stdc++.h>

using namespace std;
using pii = pair<int, int>;
using graph = vector<vector<pii>>;

int dist[101];
bool visit[101];
bool reachable[101][101];
bool inque[101];
int update[101];
int backward[101];

bool spfa(graph &al);

int main()
{
    fill(dist, dist + 101, -1e9);
    dist[1] = 0;
    ios::sync_with_stdio(false); cin.tie(0);

    int v, e;
    cin >> v >> e;

    graph adj(v + 1);

    for (int i = 0; i < e; ++i)
    {
        int go, to, fee;
        cin >> go >> to >> fee;
        adj[go].push_back({to, fee});
        reachable[go][to] = true;
    }

    for (int c = 1; c <= v; ++c)
        for (int i = 1; i <= v; ++i)
            for (int j = 1; j <= v; ++j)
                if (reachable[i][c] && reachable[c][j])
                    reachable[i][j] = true;
    
    bool res = spfa(adj);

    if (!res)
    {
        cout << -1;
        return 0;
    }

    vector<int> path;
    int printer = v;

    while (1)
    {
        path.push_back(printer);
        if (printer == 1)
            break;
        printer = backward[printer];
    }

    for (auto t = path.rbegin(); t != path.rend(); ++t)
        cout << *t << ' ';
}

bool spfa(graph &al)
{
    queue<int> q;
    q.push(1);
    inque[1] = true;
    ++update[1];

    int last = al.size() - 1;

    while (q.size())
    {
        auto cur = q.front();
        q.pop();

        inque[cur] = false;
        if (!reachable[cur][last])
            continue;

        for (auto item: al[cur])
        {            
            if (dist[item.first] < dist[cur] + item.second)
            {
                dist[item.first] = dist[cur] + item.second;
                backward[item.first] = cur;

                if (!inque[item.first])
                {
                    ++update[item.first];

                    if (update[item.first] >= last)
                        return false;

                    q.push(item.first);
                    inque[item.first] = true;
                }
            }
        }
    }

    return true;
}

 

728x90
728x90

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

백준 20530 - 양분  (0) 2021.01.01
[USACO] 백준 15591 - MooTube (Silver)  (0) 2020.11.14
백준 11779 - 최소비용 구하기 2  (0) 2020.08.13
[ICPC] 백준 5719 - 거의 최단 경로  (0) 2020.08.13
[ICPC] 백준 9019 - DSLR  (0) 2020.06.16