[BOJ] 3665번 최종 순위 - Python

"위상 정렬"

Posted by Yongmin on October 6, 2021

문제

최종 순위

풀이

위상 정렬에 대한 문제이다. 해당 index보다 뒷순위에 해당하는 것들이 담긴 인접 리스트와 뒤에 몇명이 있는지를 나타내는 degree배열을 선언해준다.
예를 들어, 5 4 3 2 1 순위라면 5 -> 4, 3, 2, 1 // 4 -> 3, 2, 1 // 3 -> 2, 1 … 이런식이다.
바뀐 값이 나오면 인접 리스트를 수정해주고, degree 배열의 값을 update해준다.
위상 정렬을 진행하기 위해 queue에 넣는데, impossible되는 경우는 초기에 q에 아무 것도 안들어가는 경우, 또 들어가더라도, 한번에 2개 이상이 들어가는 경우(degree값이 같은 경우), 혹은 degree값이 음수가 되는 경우이다.
또, 결과를 담은 리스트에 기존의 팀 수 만큼 담기지 않았다면 이상하다는 것이므로 impossble을 출력한다.
작년에 확실한 순위가 정해져있기 때문에 확실한 순위를 찾을 수 없는 경우는 없다.
Reference를 참조하였다.

소스 코드

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
import sys
import collections as cl
from math import *


testcase = int(sys.stdin.readline())

for _ in range(testcase):
    n = int(sys.stdin.readline())
    
    rank = list(map(int, sys.stdin.readline().split()))
    
    vector = [[] for _ in range(n+1)]
    #간선 생성

    degree = [0 for _ in range(n+1)]
    
    for i in range(n-1):
        for j in range(i+1, n):
            vector[rank[i]].append(rank[j])
            degree[rank[j]] += 1

    # 인접리스트 작성, 뒤에 몇명 있는지 나타내는 degree 배열

    m = int(sys.stdin.readline())

    for _ in range(m):
        a, b = map(int, sys.stdin.readline().split())
        check = True

        for i in vector[a]: 
            if i == b:
                vector[a].remove(b)
                vector[b].append(a)
                degree[a] += 1
                degree[b] -= 1
                check = False

        if(check):
            vector[b].remove(a)   
            vector[a].append(b) 
            degree[b] += 1
            degree[a] -= 1
    # 바뀌는 것을 반영

    

    q = cl.deque()
    
    for i in range(1, n+1):
        if degree[i] == 0:
            q.append(i)

    # 0인것 삽입

    result = True
    result_list = []

    if not q: #q에 아무것도 들어가 있지 않다면...
        result = False
    
    while q:
        if len(q)>1: #q에 한번에 두개이상이 들어가 있다면...
            result = False
            print(1)
            break

        current = q.popleft()
        result_list.append(current)
        for i in vector[current]:
            degree[i] -= 1
            if degree[i] == 0:
                q.append(i)

            elif degree[i] < 0:
                result = False
                print(2)
                break

    if(result == False or len(result_list) < n):
        print("IMPOSSIBLE")
    else:
        print(*result_list)



    


# # #