danbibibi
article thumbnail

문제

문제 바로가기> BOJ 5719번: 거의 최단 경로

5719번: 거의 최단 경로

입력은 여러 개의 테스트 케이스로 이루어져 있다. 각 테스트 케이스의 첫째 줄에는 장소의 수 N (2 ≤ N ≤ 500)과 도로의 수 M (1 ≤ M ≤ 104)가 주어진다. 장소는 0부터 N-1번까지 번호가 매겨져 있

www.acmicpc.net

 

풀이

다익스트라를 돌리고, 역방향 그래프를 만들어서 bfs 탐색을 진행하면, 해당 경로가 최단 경로인지 판별이 가능하다.

예를 들어 a -> b 인 경우, 역 방향 그래프에서
a까지의 최단 경로 + a에서 b로이어지는 간선 = b까지의 최단 경로라면, 해당 간선은 최단 경로에 포함된다.

이를 이용하여 최단 경로를 INF 로 변경 (사실상 제거) 해주었고, 최단 경로가 제거된 상태에서 다익스트라를 한번 더 돌려 거의 최단 경로를 구해주었다.

#include<iostream>
#include<vector>
#include<queue>
#define MAX 505
#define INF 1e9
using namespace std;

struct ROAD{int nxt, cost;};
struct PQ{
    int cur, cost;
    bool operator < (const PQ &pq) const {
        return cost > pq.cost;
    }
};

int N; // 장소의 수
int M; // 도로의 수
int S, D; // 시작점, 도착점
int dist[MAX]; // 최단 경로
bool visited[MAX]; // 방문 여부
vector<ROAD> road[MAX]; // 도로 정보
vector<ROAD> invRoad[MAX]; // 도로 정보 (역)

void init(){
    for (int i = 0; i < MAX; i++) {
        road[i].clear();
        invRoad[i].clear();
    }
}

void input(){
    cin >> N >> M;
    cin >> S >> D;

    int u, v, p;
    for (int i = 0; i < M; i++){
        cin >> u >> v >> p;
        road[u].push_back((ROAD){v, p});
        invRoad[v].push_back((ROAD){u, p});
    }
}

void dijkstra(){

    // 1. 초기화
    for (int i = 0; i < N; i++)
        dist[i] = INF;

    // 2. 시작점 처리
    priority_queue<PQ> pq;
    pq.push((PQ){S, 0});
    dist[S] = 0;

    // 3. 다익스트라
    while (!pq.empty()){
        int cur = pq.top().cur;
        pq.pop();

        for(auto n : road[cur]){
            int nxt = n.nxt;
            int ncost = dist[cur] + n.cost;
            if(ncost<dist[nxt]){
                pq.push((PQ){nxt, ncost});
                dist[nxt] = ncost;
            }
        }
    }
}

void remove_shortest(){

    // 1. 초기화
    for (int i = 0; i < N; i++)
        visited[i] = false;
    
    // 2. 시작점 처리
    queue<int> q;
    q.push(D);

    // 3. 최단 경로 제거
    while(!q.empty()){
        int cur = q.front(); q.pop();
        if(visited[cur]) continue;
        visited[cur] = true;

        for(auto n : invRoad[cur]){
            int nxt = n.nxt;
            int cost = n.cost;
            if(dist[nxt] + cost == dist[cur]){ // 최단 경로에 포함되는 경우
                q.push(nxt);
                for (int i=0; i<(int)road[nxt].size(); i++){
                    if(road[nxt][i].nxt == cur) road[nxt][i].cost = INF;
                }
            } 
        }
    }
}

void solve(){

    // 1. 최단 경로 찾기
    dijkstra();

    // 2. 최단 경로 제거
    remove_shortest();

    // 3. 거의 최단 경로 찾기
    dijkstra();

    if(dist[D]==INF) cout << "-1\n";
    else cout << dist[D] << "\n";
}

int main(){
    ios_base::sync_with_stdio(0); cin.tie(0);
    // freopen("../test/input.txt", "r", stdin);
    while(true){
        init();
        input();
        if(N==0 && M==0) break; // 입력 종료 조건
        solve();
    }
}

'문제 풀이 > 백준' 카테고리의 다른 글

BOJ 3020번: 개똥벌레  (0) 2024.03.20
BOJ 16947번: 서울 지하철 2호선  (1) 2024.03.07
BOJ 12851번: 숨바꼭질 2  (0) 2024.02.21
BOJ 1938번: 통나무 옮기기  (1) 2024.02.18
BOJ 1005번: ACM Craft  (0) 2024.02.18
profile

danbibibi

@danbibibi

꿈을 꾸는 시간은 멈춰 있는 것이 아냐 두려워하지 마 멈추지 마 푸른 꿈속으로