풀이 보관함

[C++] 백준 2307번: 도로검문 본문

problem solving/백준

[C++] 백준 2307번: 도로검문

viin 2023. 3. 5. 01:52

🔗 문제

2307번: 도로검문

 

2307번: 도로검문

그림 1은 어떤 도시의 주요 지점과 그 지점들 간의 이동시간을 나타낸 그래프이다. 그래프의 노드는 주요 지점을 나타내고 두 지점을 연결한 도로(에지)에 표시된 수는 그 도로로 이동할 때 걸리

www.acmicpc.net

 

🖍 풀이

문제를 하나씩 뜯어보면 일단 범죄자의 도주 경로와 최소 비용을 구해야 한다.

  • 경로는 양의 가중치가 있는 그래프로 주어진다.
  • 시작 지점과 도착 지점이 주어진다.

두 조건을 보아 다익스트라 기법을 이용해야 한다는 감을 잡았다.

 

어려웠던 점

최대 지연을 위해서는 모든 도로를 다 빼는 건 시간 초과에다가 틀린 접근이다.( 당ㅇ연함)

도주 경로의 도로를 빼야한다는건 알았는데 어떻게 구현할지 모르겠어서 인터넷의 도움을 받았다.

 

 

dijkstra(isCriminal, from, to)

  • isCriminal : 범죄자의 도주 경로를 구하는 중이면 true
    • true: 현재 노드가 x일 때 parent[x]에 이전 노드를 저장한다.
  • from, to: 지연 시킬 도로 from-to를 표현
    • 지연 시킬 도로에 해당하면 이동 불가하게 만든다. (코드 참고)

 

최대 지연시킬 수 있는 도로 찾기

int max_time= 0;
parent[1] = 1; // 출발점이라서 자기 자신이 부모다. 

for(int i=N; i!=parent[i]; i=parent[i])
{
    max_time = std::max(max_time, dijkstra(false, i, parent[i]));
    if(max_time == INF) break;
}
  • 범죄자의 도주 경로를 역순으로 도로를 점거 하여 최소 이동거리를 구한다.
    • 만약 도주 경로가 1-2-3-7이라면
      • 7-3, 3-2, 2-1 이 순서로 도로를 이동하지 못하게 하고 탐색한다.
  • 역순으로 진행하다가 부모가 자기 자신인 1을 만나면 종료된다.
  • 도주 경로에 있는 도로가 유일한 탈출 경로라면 max_time은 INF다.
    • 도둑 탈출 불가 루트 찾음 → 정답 : -1

 

💾  소스

#include <iostream>
#include <queue>
#include <vector>

const int INF = 987654321;

int N, M;

std::vector<int> parent;
std::vector<std::pair<int, int>> W[1001];

int dijkstra(bool isCriminal = false, const int from = -1, const int to = -1)
{
    std::priority_queue<std::pair<int, int>> pq;
    
    std::vector<int> distance (N+1, INF);
    distance[1] = 0;
    
    pq.push({0, 1}); // cost, node
    while(!pq.empty())
    {
        int cost = -pq.top().first;
        int node = pq.top().second;
        pq.pop();
        
        if(cost > distance[node])
            continue;
        
        for(int i=0; i<W[node].size(); ++i)
        {
            int next_node = W[node][i].first;
            int next_cost = W[node][i].second + cost;
            
            if(next_cost >= distance[next_node]) continue;

            
            if(isCriminal)
                parent[next_node] = node;

            if(from == node && to == next_node) continue;
            if(from == next_node && to == node) continue;

            distance[next_node] = next_cost;
            pq.push({-next_cost, next_node});
        }
    }
    return distance[N];
}

int main()
{
    int a, b, t;

    std::cin >> N >> M;

    parent.resize(N+1, -1);
    for(int i=0; i<M; ++i)
    {
        std::cin >> a >> b >> t;
        
        W[a].push_back({b, t});
        W[b].push_back({a, t});
    }
   
    int criminal_time = dijkstra(true);
    int max_time= 0;
    
    parent[1] = 1;
    for(int i=N; i!=parent[i]; i=parent[i])
    {
        max_time = std::max(max_time, dijkstra(false, i, parent[i]));
        if(max_time == INF) break;
    }
    std::cout << (max_time == INF ? -1 : max_time - criminal_time);
    
    return 0;
}