반응형

문제 출처 :


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



알고리즘 분석 :


문제 해결에 필요한 사항

1. LCA(Lowest Common Ancestor) :: http://www.crocus.co.kr/660

2. LCA 응용


일단 LCA에 대한 내용은 위의 게시물에서 확인할 수 있다.


여기서 일반적 LCA 코드와 달라진 점은


dist 배열이 생긴것이다.


이 dist배열은 루트노드(1)에서 x까지의 거리를 담아둔 것이다.


만약 우리가 lca를 알게된다면 두 정점간의 최단 거리를 구할 수 있게 된다.


그림을 통해 보자.


 



이렇게 a와 b의 최단 거리를 알고 싶다면 lca를 구하여 dist[a] - dist[lca] + dist[b] - dist[lca]를 하면 주황색 선인 두 거리가 나온다.

요약하면 dist[a] + dist[b] - 2*dist[lca]이다.


그리고 tree를 만드는 dfs과정에서 미리 루트노드(1)과의 x와의 거리를 구해두면 된다.


dist[here] += dist[parent] + val로 나타내는데 val인자는 부모노드에서 자식노드의 거리를 나타낸다. 


dist[parent]의 의미는 1에서 부모까지 내려온 거리이고 val은 부모와 자식노드의 거리이니


둘을 더하면 1에서 자식까지의 거리를 생성할 수 있다.


소스 코드 : 


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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include <iostream>
#include <cstdio>
#include <vector>
#include <cmath>
 
#define swap(a,b){int t = a; a = b; b = t;}
#define MAX_NODE 40001
 
using namespace std;
 
// depth :: 노드의 깊이(레벨)
// ac[x][y] :: x의 2^y번째 조상을 의미
int depth[MAX_NODE];
int ac[MAX_NODE][20];
 
typedef pair<intint> pii;
vector<pii> graph[MAX_NODE];
 
// 루트 노드(1)에서 x까지의 거리
long long dist[MAX_NODE];
 
int max_level;
 
// DP(ac)배열 만드는 과정
void getTree(int here, int parent, int val)
{
    // here의 깊이는 부모노드깊이 + 1
    depth[here] = depth[parent] + 1;
 
    // here이 1인 경우에는 dist[1] = 0
    // 그 외에 경우에는 루트노드에서 자신의 부모와의 거리 + 자신의 부모와 자신과의 거리를 담는다.
    if (here != 1)
        dist[here] += dist[parent] + val;
 
    // here의 1번째 조상은 부모노드
    ac[here][0= parent;
    
    // MAX_NODE에 log2를 씌어 내림을 해준다.
    max_level = (int)floor(log2(MAX_NODE));
 
    for (int i = 1; i <= max_level; i++)
    {
        // tmp :: here의 2^(i-1)번째 조상
        int tmp = ac[here][i - 1];
        ac[here][i] = ac[tmp][i - 1];
    }
 
    // dfs 알고리즘
    int len = graph[here].size();
    for (int i = 0; i < len; i++)
    {
        int there = graph[here][i].first;
        if (there != parent)
            getTree(there, here, graph[here][i].second);
    }
}
 
int main()
{
    int n, m;
 
    scanf("%d"&n);
 
    // 양방향 그래프 형성
    for (int i = 1; i < n; i++)
    {
        int from, to, val;
        scanf("%d %d %d"&from, &to, &val);
        graph[from].push_back(pii(to,val));
        graph[to].push_back(pii(from, val));
    }
 
    // make_tree에 1,0이 들어가기때문에 0은 -1로 지정
    depth[0= -1;
 
    // 루트 노드인 1번 노드부터 트리 형성
    getTree(100);
 
    // 쿼리문 시작
    scanf("%d"&m);
 
    while (m--)
    {
        int a, b;
        scanf("%d %d"&a, &b);
 
        // tmpa, tmpb는 a와 b의 원래 모습을 가지고 있는다.
        int tmpa = a;
        int tmpb = b;
 
        if (depth[a] != depth[b])
        {
            // depth[b] >= depth[a]가 되도록 swap
            if (depth[a] > depth[b])
                swap(a, b);
 
            // b를 올려서 depth를 맞춰준다.
            int j = 0;
            for (int i = max_level; i >= 0; i--)
            {
                if (depth[a] <= depth[ac[b][i]])
                    b = ac[b][i];
            }
        }
 
        int lca = a;
 
        if (a != b)
        {
            for (int i = max_level; i >= 0; i--)
            {
                if (ac[a][i] != ac[b][i])
                {
                    a = ac[a][i];
                    b = ac[b][i];
                }
                lca = ac[a][i];
            }
        }
 
        // 루트노드와 tmpa와의 거리 - 루트노드와 lca와의 거리 
        //                                 +
        // 루트노드와 tmpb와의거리 - 루트노드와 lca와의 거리
        printf("%lld\n", dist[tmpa] + dist[tmpb]- 2*dist[lca] );
    }
    return 0;
}
 
//                                                       This source code Copyright belongs to Crocus
//                                                        If you want to see more? click here >>
Crocus


반응형

'Applied > 알고리즘 문제풀이' 카테고리의 다른 글

[7894번] 큰 숫자  (0) 2017.03.15
[8012번] 한동이는 영업사원!  (0) 2017.03.15
[11437번] LCA  (0) 2017.03.15
[11438번] LCA 2  (0) 2017.03.15
[10999번] 구간 합 구하기 2  (0) 2017.03.13