| 시간 제한 | 메모리 제한 | 제출 | 정답 | 맞힌 사람 | 정답 비율 |
|---|---|---|---|---|---|
| 1 초 | 1024 MB | 1809 | 967 | 708 | 53.394% |

개의 정점과 개의 간선으로 이루어진, 사이클이 없는 방향그래프(DAG)가 주어진다.
투어리스트 곰곰이는 종종 이 그래프 위에서 여행을 떠난다. 투어리스트 곰곰이의 여행은 1번 정점에서 출발해 간선을 따라서 이동한다. 그러다가 더 이상 간선을 따라서 이동할 수 없는 경우 투어리스트의 여행은 종료된다.
투어리스트 곰곰이의 열성 팬인 팬클럽 곰곰이는 투어리스트를 만나기 위해 그래프 위의 정점 일부에서 잠복하곤 한다. 팬클럽 곰곰이가 잠복한 정점 위에 투어리스트 곰곰이가 서 있게 되면 투어리스트 곰곰이와 팬클럽 곰곰이가 만나게 된다.
오늘도 투어리스트 곰곰이는 음악을 들으면서 여행을 떠나려고 한다. 그러다가 Twice의 노래인 "YES or YES" 에서 다음과 같은 가사를 듣게 된다.
조금 쉽게 말하자면
넌 뭘 골라도 날 만나게 될 거야
Twice, YES or YES 가사 중 일부
투어리스트 곰곰이는 Twice의 노래 가사처럼, 뭘 골라도 팬클럽 곰곰이를 만나게 될 것인지 궁금해졌다.
투어리스트 곰곰이가 어떻게 이동하더라도 팬클럽 곰곰이를 만나게 된다면 "Yes" 를, 팬클럽 곰곰이를 만나지 않고 이동하는 방법이 존재한다면 "yes" 를 출력하자.
[입력]
첫째 줄에는 정점의 개수 과 간선의 개수 이 주어진다. ()
이후 줄에 걸쳐서 간선의 정보를 나타내는 두 정수 , 가 주어진다. 이는 정점 에서 정점 로 가는 간선이 있음을 의미한다. (, , )
이후 번째 줄에는 팬클럽 곰곰이가 존재하는 정점의 개수 가 주어진다. ()
이후 번째 줄에는 팬클럽 곰곰이가 존재하는 정점의 번호 가 차례대로 개 만큼 주어진다. ()
주어진 그래프는 사이클이 없음이 보장된다. 또한 두 정점을 연결하는 간선은 최대 한 개이다.
팬클럽 곰곰이가 존재하는 정점의 번호는 중복해서 주어지지 않는다.
[출력]
문제에서 설명한 조건에 맞춰서 Yes 또는 yes 를 출력한다.
bfs나 dfs로 풀면되는 문제같은데, 곰곰이가 있는 정점을 방문 처리해두고, 곰곰이와 만나게 되면, Yes를 곰곰이를 만나지 않고 이동하게 된다면 yes를 출력할 수 있게 하는 방법을 생각해보았다.
from collections import deque
n, m = map(int, input().split())
graph = [[] for _ in range(n+1)]
for _ in range(m):
a, b = map(int, input().split())
graph[a].append(b)
s = int(input())
gom = list(map(int, input().split()))
visited = [False for _ in range(n+1)]
def bfs():
q = deque()
q.append(1)
if visited[1]:
return 'Yes'
visited[1] = True
while q:
v = q.popleft()
if not graph[v]:
return 'yes'
for i in graph[v]:
if not visited[i]:
visited[i] = True
q.append(i)
return 'Yes'
for g in gom:
visited[g] = True
print(bfs())
⇒ 이렇게 구현했는데 2772ms로 시간이 너무 오래걸려서 다른 방법을 생각해 보았다.
bfs가 아니라 갈 수 있는 곳을 깊이 탐색해서 여기서 곰곰 팬클럽이 없으면 다른곳으로 이동하는 것을 생각했어야 했다. 이 방식이 너비우선탐색보다 훨씬 더 빠르게 실행될 수 있을 것이다.
따라서 bfs가 아니라 dfs를 사용하는 방식으로 다시 구현해보았다.
n, m = map(int, input().split())
graph = [[] for _ in range(n + 1)]
for _ in range(m):
a, b = map(int, input().split())
graph[a].append(b)
s = int(input())
gom = list(map(int, input().split()))
visited = [False for _ in range(n + 1)]
for g in gom:
visited[g] = True
def dfs(v):
if visited[v]:
return 'Yes'
visited[v] = True
if not graph[v]:
return 'yes'
for i in graph[v]:
if not visited[i]:
result = dfs(i)
if result == 'yes':
return 'yes'
return 'Yes'
print(dfs(1))
⇒ 이렇게 탐색했더니 런타임 에러가 발생했다. DFS를 재귀 방식으로 구현할 때 발생할 수 있는 RecursionError 또는 그래프에서의 무한 루프 등이 주요 원인이라고 생각했다.
⇒ 그래서 재귀를 사용하는 것이 아니라 stack에 쌓고 pop하는 방식을 사용해보았다.
n, m = map(int, input().split())
graph = [[] for _ in range(n + 1)]
for _ in range(m):
a, b = map(int, input().split())
graph[a].append(b)
s = int(input())
gom = list(map(int, input().split()))
visited = [False for _ in range(n + 1)]
for g in gom:
visited[g] = True
def dfs(v):
stack = [v]
while stack:
node = stack.pop()
if visited[node]:
return 'Yes'
visited[node] = True
if not graph[node]:
return 'yes'
for i in graph[node]:
if not visited[i]:
stack.append(i)
return 'Yes'
print(dfs(1))
⇒ 이 방식으로 바꾸니 그래도 2756ms로 시간이 조금은 줄어든 것을 확인할 수 있었다.
비록 시간은 오래걸리지만 해냈다는 점에서 다행이라는 생각이 들었다.
문제를 해결하는 과정에서 많은 시행착오가 있었지만, 조금이라도 시간을 줄여서 개발해냈다는 점에 큰 의의를 둔다. 다음부터는 문제를 해결할 때 가장 최적의 알고리즘이 뭔지 더 고민해야겠다는 생각이 들었다.