그래프 알고리즘 기초 - 위상정렬(topological sorting)


그래프 알고리즘 기초 - 위상정렬

위상 정렬(topological sorting)

  • 사이클이 없는 방향 그래프(비순환 그래프-Directed Acycle Graph) 에서 모든 노드를 방향성에 거스르지 않고 순서대로 나열하는 정렬 방법입니다.
  • 위상정렬에서는 진입 차수진출 차수 를 알아야 합니다.
    • 진입 차수 : 특정한 노드로 들어오는 간선의 개수
    • 진출 차수 : 특정한 노드에서 나가는 간선의 개수
  • 진입 차수가 0인 시작점을 먼저 배치 하고 그 정점에서 나가는 간선을을 제거합니다. 그 후에 그다음 진입 차수가 0 인 정점을 배치 하여 나가는 방식 입니다.
  • 항상 유일한 값으로 정렬이 되지 않아 결과에 중복이 있을수 있습니다.
  • 큐나 스택을 이용하여 구현 할 수 있습니다.
  • 알고리즘 활용 영역

위상 정렬 구현 코드(백준-문제집)

  /**
 민오는 1번부터 N번까지 총 N개의 문제로 되어 있는 문제집을 풀려고 한다. 문제는 난이도 순서로 출제되어 있다. 즉 1번 문제가 가장 쉬운 문제이고 N번 문제가 가장 어려운 문제가 된다.
 어떤 문제부터 풀까 고민하면서 문제를 훑어보던 민오는, 몇몇 문제들 사이에는 '먼저 푸는 것이 좋은 문제'가 있다는 것을 알게 되었다. 예를 들어 1번 문제를 풀고 나면 4번 문제가 쉽게 풀린다거나 하는 식이다. 민오는 다음의 세 가지 조건에 따라 문제를 풀 순서를 정하기로 하였다.

 1. N개의 문제는 모두 풀어야 한다.
 2. 먼저 푸는 것이 좋은 문제가 있는 문제는, 먼저 푸는 것이 좋은 문제를 반드시 먼저 풀어야 한다.
 3. 가능하면 쉬운 문제부터 풀어야 한다.
 
 입력 값
 4 2 > 문제의 개수 (N) 순서(M)
 4 2
 3 1
  */
  
  public static class main(String[] args) throws IOException {
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    String[] NM = br.readLine().split(" ");
    int n = Integer.parseInt(NM[0]);  //문제의 개수(노드)
    int m = Integer.parseInt(NM[1]);  //문제의 순서(간선)

    int[] count = new int[n + 1];   //진출 차수를 입력할 배열 생성
    List<Integer>[] list = new ArrayList[n + 1];  //진입 차수를 정리할 배열 생성
    for(int i = 0 ; i <= n; i++){
        list[i] = new ArrayList<>(); // 초기화
    }
    for(int i = 0; i < m; i++){  // 그래프 배열 입력
        String[] input = br.readLine().split(" ");
        int a = Integer.parseInt(input[0]);
        int b = Integer.parseInt(input[1]);
        count[b]++;
        list[a].add(b);
    }
    Queue<Integer> queue = new PriorityQueue<>(); //쉬운문제부터 풀어야 하기때문에 우선순위 큐를 사용함.
    for(int i =1; i < count.length; i++){
      if(count[i] == 0 ){
          queue.offer(i);  //진입차수가 0인 노드를 큐에 넣는다.
      }
    }
    StringBuilder sb = new StringBuilder();
    while(!queue.isEmpty()){  //큐가 비일때 까지 반복
      int node = queue.poll();
      sb.append(node).append(" ");
  
      List<Integer> nodes = list[node];
      for (Integer integer : nodes) {
          count[integer]--;    //진입차수를 줄여준다.
          if (count[integer] == 0) {  //진입차수가 0이되면 큐에 넣는다.
            queue.offer(integer);
          }
      }
    }
    System.out.println(sb);  //결과값 3 1 4 2
  }

풀이

1번 문제부터 풀경우 3번을 풀어야 1번을 풀수 있고 4번을 풀어야 2번을 풀수 있기 때문에 순서대로 정렬을 하면 3 -> 1 -> 4 -> 2 로 정렬 된다.

Back to blog