티스토리 뷰
https://www.acmicpc.net/problem/2430
쉽게 가자. 만약에 두 트리의 루트 T1, T2가 주어졌다면 어떨까?
* 1. T1과 T2에서 BFS를 돌린다.
*
2. 그래프에 모든 에지들을 T1쪽에 속하는지, T2쪽에 속하는지 분류하는 방법을 알려주자면, i - j를 잇는 에지에 대해서
(D(T1, i) + D(T1, j)) / 2와 ((D(T2, i) + D(T2, j)) / 2를 생각해보자. (무게 중심) 두
값중 작은 쪽이 존재한다면, 그 쪽에 속하는 에지로 보내버리고, 만약에 두 값이 같다면 이건 거울대칭트리 그래프가 아니다. 이렇게
하면 두개의 트리가 만들어 진다. 트리가 아닌 다른 게 만들어졌다면 (E != V-1) NO 찍자.
* 3.
리프 번호가 같고, 트리의 구성 에지가 같은지를 체크하는 것이 목표이다. Tree Isomorphism이라고 불리는 문제인데,
경시 대회에서 쓰기 가장 좋은 방법은 해싱이라고 생각한다. 깊이 차를 충돌 없이 잘 표현하며, 서브트리의 rotation에 상관
없는 표기법을 잘 사용하면(...) 풀 수 있다. 리프일때는 노드 인덱스를 반환하는 걸 잊지 말아야 함.
트리 의 루트 T1, T2의 경우의 수가 O(N^2)니 이렇게 O(N^2M) 알고리즘을 만들 수 있다. (사실 해싱 쓰는 tree isomorphism이 O(NlgN)이긴 한데.. 저 문제는 해싱 없이 O(N)에 풀린다고 하니 이 부분은 넘어가자.) 이제 문제는 T1과 T2를 구하는 쪽으로 넘어갔다.
T1과 T2를 구하는 방법을 조금 쉬운 걸 찾으려고 했지만 그런게 잘
나오진 않았다. 나는 두개의 사이클을 활용했다. 임의의 degree가 3인 점을 잡고, 이 점을 지나는 두개의 사이클을 구하자.
(인접한 두개의 간선을 block하고 bfs를 돌리면 쉽게 구할 수 있다.) 그러한 점이 없거나 그러한 점에서 사이클이 안 생길 수
있는데 이건 나중에 설명.
두 사이클이 공통으로 겹치는 경로를 구한다. 경로의 정확한 중점이 존재한다면 찍자.
이 중점은 두 트리의 리프이다. 리프인 고로 degree가 2고, 양옆에 있는 정점을 루트로 잡으면 된다. 이 문단에서 뭔가
안되는 부분이 존재한다면 NO를 찍으면 된다.
이제 두개의 케이스를 설명한다.
* 1. degree가 3인 점을 잡았는데 사이클이 안 생겼다 -> 루트가 리프인 경우가 아니다. 루트가 리프가 아니면 절대 저런 일은 일어나지 않는다. 루틴이 돌기 전에 그래프 전체에서 degree가 1인 점 두개를 찾자. 1개나 3개 이상이면 NO, 2개면 그 두개의 점이 루트일 것이다. 0개면 위에 적힌 루틴을 돌린다.
* 2. degree가 3인 점이 없다 -> 원본 트리에서 degree가 3인 점이 없었다는 뜻이다. 트리가 일직선인 경우인데, 루트가 일직선의 끝에 있었다면 1번에 의해서 걸러지고, 루트가 일직선 중간에 있었다면 이 그래프는 사이클 하나로만 이루어진 그래프이다. 일단 그런 경우인지 보고, 그런 경우라면 n의 홀짝에 따라 답이 결정된다.
cpp : https://github.com/koosaga/olympiad/blob/master/BOI/boi11_treemirror.cpp 대략 4000byte 정도 나왔다. 코드는 맘먹고 짜면 의외로 짤만하다.
'공부 > Problem solving' 카테고리의 다른 글
Wunder Fund Round 2016 (Div1 + Div2) (0) | 2016.01.30 |
---|---|
Path Cover of DAG (0) | 2016.01.03 |
some problem solving 2016.01 (0) | 2016.01.03 |
시간이 돈 (Balkan OI 2011) (0) | 2015.12.28 |
케이크 (JOI Spring Camp 2013) (0) | 2015.12.27 |
- Total
- Today
- Yesterday