www.acmicpc.net/problem/1504

 

1504번: 특정한 최단 경로

첫째 줄에 정점의 개수 N과 간선의 개수 E가 주어진다. (2 ≤ N ≤ 800, 0 ≤ E ≤ 200,000) 둘째 줄부터 E개의 줄에 걸쳐서 세 개의 정수 a, b, c가 주어지는데, a번 정점에서 b번 정점까지 양방향 길이 존�

www.acmicpc.net


  • 간선 간 양의 거리가 주어진 다익스트라 문제인데, 중간에 반드시 거쳐야 하는 점 두개가 주어진다.
  • 처음엔 해당 노드들을 방문했는지 체크하는 요소를 추가해서 검사하려 했는데, 상당히 복잡해질 것 같아서 그만뒀다.
  • 대신, 그냥 다익스트라로 1 ~ v1 ~ v2 ~ N 까지 각각의 최단거리들을 구해서 더한 값이 최단거리가 된다.
  • 하지만 v1 과 v2 중 어디를 먼저 지나가냐에 따라 거리가 달라질 수 있기 때문에, 둘 다 구해서 더 작은 값을 취해준다.

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

#define INF 10e8

using namespace std;

int n, e, answer;
int a, b, c;
int v1, v2;
vector<pair<int,int>> nodes[801];

int dijkstra(int start, int end)                            // 시작점과 끝점이 주어졌을 때 다익스트라로 최단거리 반환
{
    int ret = -1;
    vector<int> visited(n+1, INF);                          // visited 배열은 각 인덱스(노드)의 최단거리 저장, INF 로 초기화

    priority_queue<pair<int,int>> pq;
    pq.push(pair<int,int>(0, start));                       // start 부터 시작
    visited[start] = 0;

    while(pq.size())
    {
        int pos = pq.top().second;                          // 이번 노드를 꺼내서 확인
        int dist = -pq.top().first;
        pq.pop();

        for(int i = 0 ; i < nodes[pos].size() ; i++)        // 노드에 연결되어있는 다른 노드들 모두 확인하는데
        {
            int nextPos = nodes[pos][i].second;
            int nextDist = nodes[pos][i].first;
            
            if(dist + nextDist < visited[nextPos])          // 최단거리 갱신이 가능한 노드들만 집어넣음
            {
                visited[nextPos] = dist + nextDist;         // 업데이트 해주고 큐에 푸시함
                pq.push(pair<int,int>(-(dist + nextDist), nextPos));
            }
        }
    }

    return (visited[end] == INF ? -1 : visited[end]);
}

int main()
{
    cin.tie(0);
    ios_base::sync_with_stdio(0);

    cin >> n >> e;
    for(int i = 0 ; i < e ; i++)
    {
        cin >> a >> b >> c;
        nodes[a].push_back(pair<int,int>(c, b));                        // 간선 연결 (양방향)
        nodes[b].push_back(pair<int,int>(c, a));
    }
    cin >> v1 >> v2;

    int a1 = dijkstra(1, v1) + dijkstra(v1, v2) + dijkstra(v2, n);      // 1 ~ v1 ~ v2 ~ n 까지의 최단거리
    int a2 = dijkstra(1, v2) + dijkstra(v2, v1) + dijkstra(v1, n);      // 1 ~ v2 ~ v1 ~ n 까지의 최단거리
    answer = min(a1, a2);
    if (answer == - 3) answer = -1;                                     // 둘 중 작은 값을 택한다

    cout << answer << endl;
}

 


  • 1등 소스코드 참고 : www.acmicpc.net/source/5135510e
  • int 입력을 따로 클래스를 만들어서 사용하셨다.
  • 다익스트라를 6번 돌릴 필요 없이, 한번 돌렸을 때 visited 배열에 각각 해당 노드에서 다른 모든 노드들의 최솟값이 정해지므로, 1번 노드, v1 노드, v2 노드 3개에 대해서만 배열을 만들면 재활용이 가능하다.
#include <cstdio>
#include <vector>
#include <queue>
#include <algorithm>
#include <utility>
#include <cctype>
using namespace std;
typedef pair<int,int> pii;

class FastIO
{
private:
    int fd;
    int bufsz;
    char* buf;
    char* cur;
    char* end;

public :
    FastIO(int _fd = 0, int _bufsz = 1 << 20) : fd(_fd), bufsz(_bufsz)
    {
        buf = cur = end = new char[bufsz];
    }
    ~FastIO()
    {
        delete[] buf;
    }
    bool readbuf()
    {
        cur = buf;
        end = buf + bufsz;
        while(true)
        {
            size_t res = fread(cur, sizeof(char), end - cur, stdin);
            if(res == 0) break;
            cur += res;
        }
        end = cur;
        cur = buf;
        return buf != end;
    }
    int readint()
    {
        while(true)
        {
            if(cur == end) readbuf();
            if(isdigit(*cur) || *cur == '-') break;
            ++cur;
        }
        bool sign = true;
        if(*cur == '-')
        {
            sign = false;
            ++cur;
        }
        int ret = 0;
        while(true)
        {
            if(cur == end && !readbuf()) break;
            if(!isdigit(*cur)) break;
            ret = ret * 10 + (*cur - '0');
            ++cur;
        }
        return sign? ret : -ret;
    }
};

FastIO fio;
const int INF = 10e8;
int n, e, s, t;
vector<pii> nodes[801];

void dijkstra(int st, vector<int>& d)
{
    priority_queue<pii> pq;
    d[st] = 0;
    pq.push({0, st});
    while(pq.size())
    {
        auto r = pq.top();
        pq.pop();
        int pos = r.second;
        int dist = -r.first;
        for(auto& iter : nodes[pos])
        {
            int nextPos = iter.first;
            int nextDist = dist + iter.second;
            if(nextDist < d[nextPos])
            {
                d[nextPos] = nextDist;
                pq.push({-nextDist, nextPos});
            }
        }
    }
}

int main()
{
    n = fio.readint();
    e = fio.readint();
    for(int i = 0 ; i < e ; i++)
    {
        int u = fio.readint();
        int v = fio.readint();
        int w = fio.readint();
        nodes[u].push_back({v, w});
        nodes[v].push_back({u, w});
    }
    s = fio.readint();
    t = fio.readint();

    vector<int> d1(n+1, INF);
    vector<int> ds(n+1, INF);
    vector<int> dt(n+1, INF);
    dijkstra(1, d1);
    dijkstra(s, ds);
    dijkstra(t, dt);
    int ans1 = d1[s] + ds[t] + dt[n];
    int ans2 = d1[t] + dt[s] + ds[n];
    int answer = min(ans1, ans2);
    if(answer >= INF) printf("%d\n", -1);
    else printf("%d\n", answer);
    return 0;
}

 

'PS > BOJ' 카테고리의 다른 글

[백준] 14888.cpp : 연산자 끼워넣기  (0) 2020.09.05
[백준] 2193.cpp : 이친수  (0) 2020.09.04
[백준] 17144.cpp : 미세먼지 안녕!  (0) 2020.09.02
[백준] 17070.cpp : 파이프 옮기기 1  (0) 2020.09.01
[백준] 14502.cpp : 연구소  (0) 2020.08.31

+ Recent posts