할머니의 콤퓨타 도전기

위상 정렬 (Topology Sort) 본문

Algorithm/Algorithm 정리

위상 정렬 (Topology Sort)

ji.o.n.e 2021. 1. 30. 20:34

위상 정렬

  • 순서가 정해져 있는 작업을 차례대로 수행해야할 때 그 순서를 결정해주기 위해 사용하는 알고리즘
  • DAG (Directed Acyclic Graph: 사이클이 발생하지 않는 방향 그래프)에만 적용 가능
  • 사이클이 발생하는 경우 위상 정렬을 수행할 수 없음
  • 위상 정렬은 시작점이 존재해야함. 사이클 그래프에서는 시작점 찾을 수 없음. 불가능
  • 위상 정령은 두 가지의 해결책 보여줌
    1. 현재 그래프는 위상 정렬이 가능?
    2. 가능하다면, 그 결과는?

구현 방법

  1. 진입 차수가 0인 정점을 큐에 삽입
  2. 큐에서 원소를 꺼내 연결된 모든 간선 제거
  3. 간선 제거 이후에 진입차수가 0이된 정점을 큐에 삽입
  4. 큐가 빌 때 까지 2~3번 과정 반복
  • 모든 원소를 방문하기 전에 큐가 빈다면, 사이클이 존재하는 것
  • 모든 원소를 방문했다면 큐에서 꺼낸 순서가 위상정렬의 결과

 

관련 문제

www.acmicpc.net/problem/2252

 

2252번: 줄 세우기

첫째 줄에 N(1≤N≤32,000), M(1≤M≤100,000)이 주어진다. M은 키를 비교한 회수이다. 다음 M개의 줄에는 키를 비교한 두 학생의 번호 A, B가 주어진다. 이는 학생 A가 학생 B의 앞에 서야 한다는 의미이

www.acmicpc.net

코드 구현

#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
vector<int> v[32001];
int n, m;
int inDegree[32001];
int result[32001];
void topologySort()
{
    queue<int> q;
    for (int i = 1; i <= n; i++)
    {
        if (inDegree[i] == 0)
            q.push(i);
    }

    // 정렬이 완전히 수행되려면 정확히 n개의 노드 방문
    for (int i = 1; i <= n; i++)
    {
        int x = q.front();
        q.pop();
        result[i] = x;

        for (int i = 0; i < v[x].size(); i++)
        {
            int y = v[x][i];
            if (--inDegree[y] == 0)
                q.push(y);
        }
    }

    for (int i = 1; i <= n; i++)
    {
        cout << result[i] << ' ';
    }
}
int main()
{

    cin >> n >> m;
    for (int i = 0; i < m; i++)
    {
        int a, b;
        cin >> a >> b;
        v[a].push_back(b);
        inDegree[b]++;
    }
    topologySort();
}

'Algorithm > Algorithm 정리' 카테고리의 다른 글

최소공배수(LCM)와 최대공약수(GCD)  (0) 2021.02.12
Floyd Warshall 알고리즘  (1) 2021.02.06
Knapsack 알고리즘  (0) 2021.01.30
다익스트라(Dijkstra) 알고리즘  (0) 2021.01.26
트리의 지름 증명  (2) 2021.01.17
Comments