BOJ 1504

특정한 최단경로

문제출처

문제 해석

  • 주어진 두 정점을 반드시 거치면서 1번에서 N번 정점으로 가기 위한 최단 거리를 구하는 문제입니다.
  • 정점과 간선을 여러번 이용할 수 있습니다.

설계(10)

  • 다익스트라 알고리즘을 이용하는 문제입니다.
  • 여기서 특이한 점은 정점 v1,v2를 무조건 지나가야 한다는 점입니다.
  • 두개의 정점을 거친 상태를 표시하기 위해서 dist[N][2][2]배열을 사용합니다.
  • {현재정점, v1 지났는지 체크, v2 지났는지 체크, 최단거리}정보를 이용하여 우선순위큐로 탐색을 진행합니다.

구현(30)

코드
#include <iostream>
#include <queue>
#include <cstring>
#include <vector>

using namespace std;

#define MAXN 801
struct node{
    int cur,cnt_v1,cnt_v2,w;
    bool operator <(const node& a)const{
        return a.w < w;
    }
};
int dist[MAXN][2][2];
vector<pair<int,int> > adj[MAXN];
priority_queue<node> pq;
int N,E,v1,v2;
int dijkstra(){
    if (v1 == 1) {
        pq.push({1,1,0,0});
        dist[1][1][0] = 0;
    }
    else {
        pq.push({1,0,0,0});
        dist[1][0][0] = 0;
    }
    while (!pq.empty()){
        int cur = pq.top().cur;
        int cur_v1 = pq.top().cnt_v1;
        int cur_v2 = pq.top().cnt_v2;
        int cur_w = pq.top().w;
        pq.pop();
        if (dist[cur][cur_v1][cur_v2]!= cur_w) continue;
        for (int i = 0 ;i < adj[cur].size(); i++){
            int next = adj[cur][i].first;
            int next_w = adj[cur][i].second + cur_w;
            int next_v1 = cur_v1;
            int next_v2 = cur_v2;
            if (next == v1 && !cur_v1){
                next_v1++;
            }
            else if (next == v2 && !cur_v2){
                next_v2++;
            }
            if (dist[next][next_v1][next_v2]== -1 || dist[next][next_v1][next_v2] > next_w){
                dist[next][next_v1][next_v2] = next_w;
                pq.push({next,next_v1,next_v2,next_w});
            }
        }
    }
    return dist[N][1][1];
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    memset(dist,-1,sizeof(dist));
    cin >> N >> E;
    while (E--){
        int u,v,w;
        cin >> u >> v >> w;
        adj[u].push_back({v,w});
        adj[v].push_back({u,w});
    }
    cin >> v1 >> v2;
    cout << dijkstra() <<"\n";
    return 0;
}
디버깅
  • 처음에 v1와 v2중 하나를 지나면 카운트하도록 구현하는 실수를 하였습니다.
  • 반례로, 같은 v1을 두번 지나고 v2를 지나지 않았는데 모두 지난 것으로 인식되는 오류가 나올 수 있습니다.
제출결과
  • 48 ms

마무리

  • 다익스트라 알고리즘을 응용한 문제입니다. 8달전에 풀이한 적이 있지만 재채점으로 WA가 나왔길래 다시 한번 풀어봤습니다.
  • 당시에는 다익스트라를 총 6번이용하여 구현하였지만, 이번에는 한번만에 원하는 거리를 구할 수 있도록 최적화하였습니다.