일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- Segment Tree
- BOJ
- Eulerian path
- 백준
- POJ
- Eulerian circuit
- CS Academy
- backtracking
- Dag
- flows
- mathematics
- Shortest path
- graph
- Greedy
- Cycle detecting
- Euler circuit
- DynamicProgramming
- Euler path
- GCD
- disjoint-set
- dynamic programming
- hashing
- graph modeling
- Algospot
- scc
- bitmask
- implementation
- BST
- BFSDFS
- Sieve_of_Eratosthenes
- Today
- Total
그냥 하는 노트와 메모장
BOJ 11097 - 도시계획 본문
* BOJ 11097 도시계획 (https://www.acmicpc.net/problem/11097)
[ 분류 - SCC(Strongly connected components) ]
다소 까다로운 문제? 였다. 반면 접근 방식이 매우 여러가지라 아래 해설도 그 중 하나라고 봐주시면 되시겠당 :)
문제가 물어보는 것은 플로이드의 결과라고 생각할 수 있는 인접 행렬이 주어졌을 때, 이를 구성할 수 있는 가장 적은 도로를 쓰는 도로망을 구성하는 것이다. 그리고 일방통행 도로이기 때문에 방향 그래프인 것을 알 수 있다.
이 문제를 "최대한 도로를 지우는" 과정으로 볼 수 있다. 인접 행렬에서 지울 수 있는 도로를 모두 지워야 최소 크기의 도로망을 구성할 수 있기 때문이다.
임의의 정점에 대해서 생각해보자. 정점 A에서 정점 B로 가는 A->B 도로가 있을 때, 삭제 판단을 해야한다고 가정해보자.
만약 A에서 B로 가는 경로가 이 도로로 유일하다면 절대로 지울 수 없다. 지운다면 해당 인접 행렬 값에 0이 발생하기 때문이다. 그렇다면 A와 연결된 임의의 도시 X, 그리고 이 X가 B로 갈 수 있다면 A->B를 지울 수 있다. 따라서 아래처럼 결론을 낼 수 있다.
∴ A->X->B 라면 A->B는 삭제할 수 있다.
하지만 이 명제는 A와 B가 사이클을 이룰 때 논리적으로 맞다고 할 수 없다. 재귀적으로 파고들기 때문인데, 이를 피하기 위해선 사이클을 이루는 정점들끼리 모아줄 필요가 있다. 가령 아래의 구성인 경우 A, B, C 모두 갈 수 있으나 결국인 필요한 도로의 수는 3개 밖에 되지 않는다.
따라서 사이클을 이루는 정점에 대한 도로 설정과 사이클을 이루지 않는 정점에 대한 도로 설정을 달리 해줘야 한다.
이를 위해 SCC 알고리즘을 사용해야 한다. 사이클을 이루는 정점 집합을 SCC로 묶어주고, SCC가 DAG이기 때문에 사이클을 이루지 않는 정점 처리를 여기서 해줘야 한다.
- SCC 간의 도로 삭제 여부 판단
우선 SCC 그래프는 DAG이기 때문에 위상 정렬이 가능하다. 따라서 판단을 이 순서에 따라 맞춰서 진행한다.
현재 방문하는 SCC를 u라고 할 때, 자식들을 v1, v2, v3, ..., vn 이라고 하자. 그렇다면 u->v1을 지우기 위해서는 k=[2, n]에 대해 u->vk->v1이 하나 이상 있어야 한다. 사실 이 처리 때문에 머리 좀 썩혔는데, 새로운 인접 행렬을 그려서(주어진 인접 행렬은 도시 간의 인접 행렬이고 지금 만드려는 행렬은 SCC의 행렬), 자식들이 갈 수 있는 모든 SCC에 대해 각각 처리를 해주고 그 값을 합해주자.
이는 SCC 처리이기 때문에 처음엔 SCC X에서 SCC Y로 갈 수 있는 도로가 하나 이상이기 때문에 이를 "하나"로 보기 위해서 boolean으로 OR연산 해줘서 하나로 퉁쳐준다. X에서 Y로 가는 도로를 하나만 건설하면 되기 때문이다.
그리고 이 더해준 것을 통해 vk로 갈 수 있는 경로를 O(1)로 알 수 있다. 만약 이 값이 1이라면 해당 SCC로 갈 수 있는 경우의 수는 단일 한 가지이기 때문이다.
(이 과정은 좀 설명이 뭐같으므로 소스를 보길 추천합니당.. ㅠ)
이렇게 하면 사이클을 이루지 않는 SCC의 도로를 구성할 수 있다.
나머지는 사이클을 이루는 SCC 내부의 처리는 단순히 하나씩 이으며 원을 만들도록 구성해주면 최소가 된다.
- 코드
'Solved problems' 카테고리의 다른 글
BOJ 2981 - 검문 (0) | 2018.06.24 |
---|---|
BOJ 7806 - GCD! (0) | 2018.06.24 |
BOJ 9376 - Jailbreak(탈옥) (0) | 2018.06.08 |
BOJ 1591 - 수열 복원 (0) | 2018.06.04 |
BOJ 2889 - 레스토랑 (RESTORAN) (1) | 2018.06.04 |