백준 텀 프로젝트 9466 파이썬
- CS/BOJ
- 2022. 2. 22.
7달 전에 한 10트 도전해서 안되서 포기하고, 오늘 다시 풀어봤다. 오늘도 의기양양하게 풀었으나 82%에서 TLE 발생해서 뭐지뭐지 한참을 고민했다. 결론은 어거지로 푼 거 같으니 며칠 내로 기억이 희미해질 쯤에 다시 풀어봐야겠다.
82% 시간 초과 해결을 위해서 거의 4시간을 붙잡고 있었던 거 같다. 82%에서 시간초과가 발생하는 이유는 간단한다. 탐색하는 모수가 너무 과하기 때문이다. 즉, 탐색 모수를 최소화 해야한다.
사이클이 형성되는 경우는 다음과 같이 2가지가 있다.
1. 1 → 2 → 3 → 4 → 1
2. 1 → 2 → 3 → 4 → 5 → 3
1번은 대부분의 사람들이 잘 처리하지만, 나 같이 TLE가 발생한 사람들은 2번에서 처리하는 방법에서 많이 헤맸던 거 같다.
2번을 통해서 사이클을 확인하게 되더라도 3,4,5뿐만 아니라 1,2을 모두 탐색하지 않아도 된다. 왜냐하면 3,4,5가 싸이클이 만들어지면서 1,2는 싸이클이 만들어지지 않는 것이 확정되었기 때문이다. 따라서 DFS로 탐색을 할 때, 싸이클은 싸이클이라고 표시해주고, 싸이클이 안 만들어진 곳은 앞으로 방문하지 않아도 된다는 것을 잘 기록해줘야한다.
이렇게 하면 모든 노드는 최대 각 2n번만 탐험하면 된다. 따라서 문제의 해결이 가능해지는 것이다.
import sys
def init(my_list):
for i in list(map(int,sys.stdin.readline().split())):
my_list.append(i)
return my_list
def solsol(start_point):
global ans
#DFS 용
stack = [start_point]
#경로 체크용
d_stack = [start_point]
while stack :
now_point = stack.pop()
next_point = my_list[now_point]
# 한번도 방문한 적이 없는 경우, 계속 방문한다.
if v[next_point] == 0 :
v[next_point] = now_point
stack.append(next_point)
d_stack.append(next_point)
# 한번이라도 방문한 적이 있는 경우
else :
# 이미 경로가 없다고 판별된 곳
if v[next_point] == -1 :
break
# 사이클이 형성된 곳
if v[next_point] != 9876543210:
while d_stack:
point = d_stack.pop()
if v[point] != 9876543210 :
ans +=1
v[point] = 9876543210
if point == next_point:
break
while d_stack :
point = d_stack.pop()
v[point] = -1
for _ in range(int(sys.stdin.readline().rstrip())):
n = int(sys.stdin.readline().rstrip())
my_list = [0]
v = [0 for _ in range(n+1)]
my_list = init(my_list)
ans = 0
for student in range(1, n+1):
if my_list[student] == student :
v[student] = 9876543210
ans +=1
for student in range(1, n+1):
if v[student] == 0 :
solsol(student)
print(n - ans)
'CS > BOJ' 카테고리의 다른 글
백준 3197 백조의 호수 파이썬 (0) | 2022.02.24 |
---|---|
백준 6593 상범빌딩 파이썬 (0) | 2022.02.24 |
백준 11967 불켜기 파이썬 (0) | 2022.02.22 |
백준 16920 확장게임 (0) | 2022.02.21 |
백준 22862 가장 긴 짝수 연속한 부분 수열 (large) (0) | 2022.02.21 |