728x90
https://www.acmicpc.net/problem/14725
14725번: 개미굴
첫 번째 줄은 로봇 개미가 각 층을 따라 내려오면서 알게 된 먹이의 정보 개수 N (1 ≤ N ≤ 1000)개가 주어진다. 두 번째 줄부터 N+1 번째 줄까지, 각 줄의 시작은 로봇 개미 한마리가 보내준 먹이 정
www.acmicpc.net
트라이, Trie 라는 자료구조를 사용하는 기본 문제입니다. 트리 구조를 사용해 문자열 검색에 최적화된 자료구조 입니다. dev-diary 라는 문자열을 저장한다고 하면 d, e, v, - , d, i, a, r, y 를 순서대로 하위노드로 입력시키며 특정 문자열로 시작하는 문자열을 검색하기 쉽게 만듭니다. 구현은 클래스로 구현할 수 있으며 기본 구현과 문제를 위해 변형한 코드를 주석으로 분리해 놓았습니다.
def solution(N, data_list):
# 트라이 자료구조
trie = Trie()
# 최상단 노드 리스트
top_nodes = set()
# 데이터 리스트 순회하며 데이터 삽입
for data in data_list:
# 최상단 노드 기록
top_nodes.add(data[1])
# 트라이 삽입 함수
trie.insert(data[1:])
# 트라이 탐색
for node in sorted(list(top_nodes)):
# starts_with 함수
trie.starts_with([node])
# 트라이에 들어갈 노드 클래스
class Node(object):
# 초기화
def __init__(self, key, data=None):
self.key = key
self.data = data
self.children = {}
# 문제에서 DFS 쓸거라 추가
self.visited = 1
# 트라이 자료구조 클래스
class Trie:
# 초기화
def __init__(self):
# 최상위 노드는 빈 노드로 설정
self.head = Node(None)
# 삽입 함수, DFS 의 역과정이라고 생각하면 됨
def insert(self, string_list):
# head(최상위 노드) 먼저
current_node = self.head
# 문자열 리스트 순회
for string in string_list:
# 현재 노드의 자식(children) 에 해당 문자열이 없다면
if string not in current_node.children:
# 자식 노드 선언 및 추가
# 아래에 하나의 문자열을 쌓아가는 과정
current_node.children[string] = Node(string)
# 다음 문자열에 해당하는 노드로 이동
current_node = current_node.children[string]
# 문자열 리스트 끝이라면 해당 문자열이 무슨 문자열인지 data 추가
current_node.data = string_list
# 검색 함수, DFS 와 비슷하다고 생각하면 됨
def search(self, string_list):
# head(최상위 노드) 먼저
current_node = self.head
# 문자열 리스트 순회
for string in string_list:
# 해당 문자열이 현재 노드의 자식중에 있으면
if string in current_node.children:
# 해당 노드로 이동
current_node = current_node.children[string]
# 없으면
else:
return False
# 문자열 끝까지 탐색했고 문자열의 마지막 문자에 해당하는 노드에 데이터가 있으면
if current_node.data:
return True
# 없으면
else:
return False
# 임의의 문자열 리스트로 시작하는 문자열 리스트가 있는지 확인
# 주어진 임의의 문자열 리스트 끝에서 DFS 의 방식으로 탐색
# 원래 기본 값에서는 BFS 로 탐색, 문제에 맞춰서 변형
def starts_with(self, string_list):
# 데크
from collections import deque
# -----
# # BFS 를 위한 큐
# queue = deque([])
# -----
# DFS 를 위한 스택
stack = []
# 문자열을 저장할 리스트
data_list = []
# head(최상위 노드) 먼저
current_node = self.head
# 주어진 임의의 문자열 리스트 끝까지 이동
for string in string_list:
# 해당 문자열이 현재 노드의 자식중에 있으면
if string in current_node.children:
# 해당 노드로 이동
current_node = current_node.children[string]
# 없으면
else:
# 주어진 임의의 문자열 리스트로 시작하는 문자열 리스트 없음
return None
# -----
# # 큐에 현재 노드 삽입
# queue.append(current_node)
# -----
# 스택에 현재 노드 삽입
stack.append([current_node, 1])
# 주어진 임의의 문자열 리스트의 끝까지 왔으면 탐색 시작
while True:
# -----
# # 큐가 비면 끝
# if not queue:
# -----
# 스택이 비면 끝
if not stack:
return data_list
# -----
# 현재 노드
#current_node = queue.popleft()
# -----
# 현재 노드, 노드 깊이
current_node, node_depth = stack[-1]
# 방문한 적 없으면 프린트
if current_node.visited:
print('-'*(node_depth-1)*2 + current_node.key)
# 현재 노드 visited 체크
current_node.visited = 0
# -----
# # 현재 노드에 데이터가 존재하면 문자열 리스트에 저장
# if current_node.data:
# data_list.append(current_node.data)
# -----
# -----
# # 현재 노드의 자식 노드들을 정렬해서 큐에 추가
# queue.extend(current_node.children.values())
# -----
# 현재 노드의 자식 노드들이 존재하면 정렬해서 스택에 추가
if current_node.children:
for idx, node in enumerate(sorted(current_node.children.values(), key=lambda x: x.key)):
# 노드의 visited 가 체크가 안되어있다면
if node.visited:
# 노드의 visited 체크
stack.append([node, node_depth+1])
break
elif idx == len(current_node.children)-1:
stack.pop()
# 없으면 팝
else:
stack.pop()
N = int(input())
data_list = [input().split() for _ in range(N)]
solution(N, data_list)
728x90
'Coding Test > BaekJoon_Python' 카테고리의 다른 글
백준 5670 <휴대폰 자판> Python (0) | 2023.12.25 |
---|---|
백준 14425 <문자열 집합> Python (0) | 2023.12.24 |
백준 1305 <광고> Python (2) | 2023.12.22 |
백준 1786 <찾기> Python (0) | 2023.12.21 |
백준 17386 <선분 교차 1> Python (0) | 2023.12.18 |