DAMPER's blog

11780. 플로이드 2 본문

Problem Solving/BOJ 문제풀이

11780. 플로이드 2

DAMPER 2022. 7. 9. 15:40
728x90

https://www.acmicpc.net/problem/11780

 

11780번: 플로이드 2

첫째 줄에 도시의 개수 n이 주어지고 둘째 줄에는 버스의 개수 m이 주어진다. 그리고 셋째 줄부터 m+2줄까지 다음과 같은 버스의 정보가 주어진다. 먼저 처음에는 그 버스의 출발 도시의 번호가

www.acmicpc.net

 

문제 설명

문제 제목처럼 플로이드-워셜 알고리즘을 한 뒤, 경로 추적을 통해 i -> j 로 가는 최소비용의 경로를 출력하는 문제이다.

 

solution

먼저 플로이드-워셜 알고리즘을 통해 최소비용 테이블은 만든다.

i에서 j로 가는 비용을 i -> k -> j 비용으로 갱신할 때, 추적 테이블에 i -> j 갈 때 k를 거쳐간다고 저장한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void floyd(vvi &dist, vvi &trace)
{
    for (int k = 1; k <= N; k++)
    {
        for (int i = 1; i <= N; i++)
        {
            for (int j = 1; j <= N; j++)
            {
                if (dist[i][j] > dist[i][k] + dist[k][j])
                {
                    dist[i][j] = dist[i][k] + dist[k][j];
                    trace[i][j] = k;
                }
            }
        }
    }
}
cs

 

최소비용 테이블과 추적 테이블이 다 채워지면 분할정복으로 경로 추적에 들어간다.

startn에서 endn 으로 갈 때, mid를 거쳐서 가므로 startn -> mid 경로를 찾고, mid -> endn 경로를 찾는다.

이 때 pv 벡터에 mid가 두 번 들어가니 중간에 pop_back을 해준다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
void find(int startn, int endn, vvi &trace, vi &pv)
{
    int mid = trace[startn][endn];
    if (mid == 0)
    {
        pv.emplace_back(startn);
        pv.emplace_back(endn);
        return;
    }
    find(startn, mid, trace, pv);
    pv.pop_back();
    find(mid, endn, trace, pv);
}
cs

 

전체 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#include <bits/stdc++.h>
 
using namespace std;
 
#define swap(a, b) (a) ^= (b) ^= (a) ^= (b)
#define endl '\n'
#define int long long
 
using pii = pair<intint>;
using vi = vector<int>;
using vvi = vector<vector<int>>;
const double EPS = 1e-9;
const int dx[] = {1-100};
const int dy[] = {001-1};
 
int N, M;
 
void floyd(vvi &dist, vvi &trace)
{
    for (int k = 1; k <= N; k++)
    {
        for (int i = 1; i <= N; i++)
        {
            for (int j = 1; j <= N; j++)
            {
                if (dist[i][j] > dist[i][k] + dist[k][j])
                {
                    dist[i][j] = dist[i][k] + dist[k][j];
                    trace[i][j] = k;
                }
            }
        }
    }
}
 
void find(int startn, int endn, vvi &trace, vi &pv)
{
    int mid = trace[startn][endn];
    if (mid == 0)
    {
        pv.emplace_back(startn);
        pv.emplace_back(endn);
        return;
    }
    find(startn, mid, trace, pv);
    pv.pop_back();
    find(mid, endn, trace, pv);
}
 
int32_t main()
{
    cin.sync_with_stdio(NULL);
    cin.tie(NULL);
    cout.tie(NULL);
 
    cin >> N >> M;
    vvi dist(N + 1vector<int>(N + 1, INT_MAX));
    vvi trace(N + 1vector<int>(N + 10));
 
    int a, b, cost;
    for (int i = 0; i < M; i++)
    {
        cin >> a >> b >> cost;
        dist[a][b] = min(dist[a][b], cost);
    }
    for (int i = 1; i <= N; i++)
        dist[i][i] = 0;
 
    floyd(dist, trace);
    for (int i = 1; i <= N; i++)
    {
        for (int j = 1; j <= N; j++)
        {
            cout << (dist[i][j] >= INT_MAX ? 0 : dist[i][j]) << ' ';
        }
        cout << endl;
    }
    for (int i = 1; i <= N; i++)
    {
        for (int j = 1; j <= N; j++)
        {
            if (i == j || dist[i][j] >= INT_MAX)
            {
                cout << 0 << endl;
                continue;
            }
            vector<int> ptrace;
            find(i, j, trace, ptrace);
            cout << ptrace.size() << ' ';
            for (int K : ptrace)
                cout << K << ' ';
            cout << endl;
        }
    }
 
    return 0;
}
cs

 

 

 

 

728x90

'Problem Solving > BOJ 문제풀이' 카테고리의 다른 글

7869. 두 원  (0) 2022.07.16
3015. 오아시스 재결합  (0) 2022.07.09
1509. 팰린드롬 분할  (0) 2022.07.04
1007. 벡터 매칭  (0) 2022.07.04
13140. Hello World!  (0) 2022.01.13