순간을 성실히, 화려함보단 꾸준함을

[boj : 8012]한동이는 영업사원! 본문

알고리즘,SQL/백준,BOJ

[boj : 8012]한동이는 영업사원!

폭발토끼 2019. 7. 20. 00:10

[문제] : https://www.acmicpc.net/problem/8012

 

8012번: 한동이는 영업사원!

문제 한동이는 경상도내를 돌아다니면서 열심히 일하는 영업사원이다. 예전에는 자기가 원하는 도시만 골라서 다닐 수 있었지만 시대가 바뀌어서 이제 그렇게는 하지 못하게 되었다. 시대가 바뀜에 따라, 한동이는 회사에서 돌아야 할 도시의 목록을 받고, 그 목록대로 도시를 여행한다. 회사에서 주는 여행지 목록은 정말 안타깝게도 최적화되어 있지가 않다. 여행을 떠나기 전에 한동이는 모든 도시를 방문하는데 걸리는 최소의 시간을 알고싶어하는데, 한동이는 경영학과라 컴퓨

www.acmicpc.net

[분류] : LCA 알고리즘

 

[조건]:

가장 핵심적이고 중요한 조건은 "도로끼리 사이클을 만들지 않는다."입니다.

이 문장은 사이클이 발생하지 않는 그래프라는 뜻이며 이는 즉,"트리"임을 암시합니다.

이 조건을 빨리 파악하면 문제를 쉽게 접근 할 수 있게 됩니다.

 

[구현 방법]:

먼저 이 문제를 풀려면 "LCA 알고리즘"의 개념에 대해 습득이 되어 있어야 되는 상태입니다.

(https://www.crocus.co.kr/660)

 

LCA(Lowest Common Ancestor) 알고리즘

LCA(Lowest Common Ancestor) 알고리즘이란? LCA 알고리즘이란 영어 해석 그대로 최소 공통 조상을 찾는 알고리즘이고, 두 정점 u, v(혹은 a, b)에서 가장 가까운 공통 조상을 찾는 과정을 말한다. 예를들어 다음..

www.crocus.co.kr

(감사합니다)

우선 트리임을 파악하고 서로 다른 노드의 거리를 구하는 문제는 lca 알고리즘의 전형적인 문제 유형이라고 생각하면 되겠습니다.한 노드와 한 노드 사이의 이동하는데 걸리는 시간은 1 이므로 노드의 depth를 가지고 답을 도출 해 낼 수 있습니다.

a 노드의 depth와 b 노드의 depth를 일단 맞추어 주고(맞추어 주는 과정에서 거리를 더해줍니다.) 두 노드의 lca를 구한 다음 a 또는 b 노드의 depth에서 lca 노드의 depth를 빼준 값을 더해주면 바로 답이 됩니다. 

 

[소스]:

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
#include<iostream>
#include<vector>
#include<cmath>
#include<algorithm>
#define SIZE 30000
 
using namespace std;
 
int n, m, max_size;
 
int ac[SIZE + 1][20], depth[SIZE + 1];
vector<int> v[SIZE + 1];
void dfs(int cur, int par);
 
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
 
    int a, b, ans = 0;
    cin >> n;
    max_size = (int)floor(log2(SIZE));
    for (int i = 0; i < n - 1; i++)
    {
        cin >> a >> b;
        v[a].push_back(b);
        v[b].push_back(a);
    }
    depth[0= -1;
    dfs(10);
 
    int x = 1, y, tmp;
    cin >> m;
    while (m--)
    {
        cin >> y;
        tmp = y;
        if (depth[x] != depth[y])
        {
            if (depth[x] > depth[y])
                swap(x, y);
            for (int i = max_size; i >= 0; i--)
            {
                if (depth[x] <= depth[ac[y][i]])
                {
                    ans += depth[y] - depth[ac[y][i]];
                    y = ac[y][i];
                }
            }
        }
        int lca = x, pre = y;
        if (x != y)
        {
            for (int i = max_size; i >= 0; i--)
            {
                if (ac[x][i] != ac[y][i])
                {
                    x = ac[x][i];
                    y = ac[y][i];
                }
                lca = ac[x][i];
            }
            ans += 2 * (depth[pre] - depth[lca]);
        }
        x = tmp;
    }
    cout << ans;
    return 0;
}
void dfs(int cur, int par)
{
    depth[cur] = depth[par] + 1;
    ac[cur][0= par;
    for (int i = 1; i <= max_size; i++)
        ac[cur][i] = ac[ac[cur][i - 1]][i - 1];
 
    for (auto u : v[cur])
    {
        if (u != par)
            dfs(u, cur);
    }
}

#어색한 표현이나 설명이 틀린부분 그리고 필요 없는 코드가 존재한다면 언제라도 태클 걸어주시면 감사하겠습니다

'알고리즘,SQL > 백준,BOJ' 카테고리의 다른 글

[boj : 2020] 부분 염기서열  (2) 2020.11.05
[boj : 12755] 수면 장애  (0) 2020.08.12
[ boj : 1939]중량제한  (0) 2019.07.07
[boj : 16434] 드래곤 앤 던전  (0) 2019.07.02
[boj : 12865]평범한 배낭  (0) 2019.06.28