14725번: 개미굴
첫 번째 줄은 로봇 개미가 각 층을 따라 내려오면서 알게 된 먹이의 정보 개수 N개가 주어진다. (1 ≤ N ≤ 1000) 두 번째 줄부터 N+1 번째 줄까지, 각 줄의 시작은 로봇 개미 한마리가 보내준 먹이
www.acmicpc.net
문제
개미는(뚠뚠) 오늘도(뚠뚠) 열심히(뚠뚠) 일을 하네.
개미는 아무말도 하지 않지만 땀을 뻘뻘 흘리면서 매일 매일을 살길 위해서 열심히 일을 하네.
한 치 앞도(뚠뚠) 모르는(뚠뚠) 험한 이 세상(뚠뚠) 그렇지만(뚠뚠) 오늘도 행복한 개미들!
우리의 천재 공학자 윤수는 이 개미들이 왜 행복한지 궁금해졌다.
행복의 비결이 개미가 사는 개미굴에 있다고 생각한 윤수는 개미굴의 구조를 알아보기 위해 로봇 개미를 만들었다.
로봇 개미는 센서가 있어 개미굴의 각 층에 먹이가 있는 방을 따라 내려가다 더 이상 내려갈 수 없으면 그 자리에서 움직이지 않고 신호를 보낸다.
이 신호로 로봇 개미는 개미굴 각 층을 따라 내려오면서 알게 된 각 방에 저장된 먹이 정보를 윤수한테 알려줄 수 있다.
로봇 개미 개발을 완료한 윤수는 개미굴 탐사를 앞두고 로봇 개미를 테스트 해보기 위해 위 그림의 개미굴에 로봇 개미를 투입했다. (로봇 개미의 수는 각 개미굴의 저장소를 모두 확인할 수 있을 만큼 넣는다.)
다음은 로봇 개미들이 윤수에게 보내준 정보다.
- KIWI BANANA
- KIWI APPLE
- APPLE APPLE
- APPLE BANANA KIWI
(공백을 기준으로 왼쪽부터 순서대로 로봇 개미가 각 층마다 지나온 방에 있는 먹이 이름을 뜻한다.)
윤수는 로봇 개미들이 보내준 정보를 바탕으로 다음과 같이 개미굴의 구조를 손으로 그려봤다.
APPLE
--APPLE
--BANANA
----KIWI
KIWI
--APPLE
--BANANA
(개미굴의 각 층은 "--" 로 구분을 하였다.
또 같은 층에 여러 개의 방이 있을 때에는 사전 순서가 앞서는 먹이 정보가 먼저 나온다.)
우리의 천재 공학자 윤수는 복잡한 개미굴들을 일일이 손으로 그리기 힘들어 우리에게 그려달라고 부탁했다.
한치 앞도 모르는 험한 이세상 그렇지만 오늘도 행복한 개미들!
행복의 비결을 알기 위해 윤수를 도와 개미굴이 어떤 구조인지 확인해보자.
입력
첫 번째 줄은 로봇 개미가 각 층을 따라 내려오면서 알게 된 먹이의 정보 개수 N개가 주어진다. (1 ≤ N ≤ 1000)
두 번째 줄부터 N+1 번째 줄까지, 각 줄의 시작은 로봇 개미 한마리가 보내준 먹이 정보 개수 K가 주어진다. (1 ≤ K ≤ 15)
다음 K개의 입력은 로봇 개미가 왼쪽부터 순서대로 각 층마다 지나온 방에 있는 먹이 정보이며 먹이 이름 길이 t는 (1 ≤ t ≤ 15) 이다.
출력
개미굴의 시각화된 구조를 출력하여라.
개미굴의 각 층을 "--" 로 구분하며, 같은 층에 여러개의 방이 있을 때에는 사전 순서가 앞서는 먹이 정보가 먼저 나온다.
예제 입출력
문제풀이
트라이(Trie) 알고리즘을 이용하는 문제다. 트라이 알고리즘은 여러 문자열 중에 임의의 문자열이 존재하는지 효율적으로 확인하는 알고리즘이다. 찾고자 하는 문자열의 길이가 n일 때, 시간복잡도는 O(n)이다. 일반적으로 Trie 클래스는 insert(), contain(), remove() 메서드를 갖는데, 이 문제에서는 insert()만 사용했다.
로봇 개미 한마리가 보낸 먹이 정보를 trie구조에 insert하기
- 첫 번째 먹이가 root 노드의 children에 존재하면 다음 먹이로 넘어간다.
- 존재하지 않으면, 새로운 노드를 생성하고 추가한다.
- computeIfAbsent(key, mappingFuntion)
Map에 지정한 key가 존재하면 해당 value를 반환하고 존재하지 않으면 mappingFunction을 실행하여 초기값을 설정한다. - 모든 먹이를 탐색하면 마지막 노드의 EndOfWord를 true로 설정한다.
trie 구조를 탐색하며 출력하기
- printNode(): depth를 매개변수로 받아 dfs와 같은 원리로 자식 노드들에 대하여 반복문을 돌면서 재귀호출하며 탐색했다.
- 같은 계층일 때, 사전 순으로 출력해야 하므로, 자식 노드들을 탐색하기 전에 children을 key 값 기준으로 정렬한 후 탐색했다.
정답코드
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int N = Integer.parseInt(br.readLine());
Trie trie = new Trie();
for (int i = 0; i < N; i++) {
StringTokenizer st = new StringTokenizer(br.readLine());
int K = Integer.parseInt(st.nextToken());
trie.insert(st);
}
trie.root.printNode(0);
br.close();
}
static class Trie {
TrieNode root;
Trie() {
root = new TrieNode();
}
void insert(StringTokenizer st) {
TrieNode node = root;
while (st.hasMoreTokens()) {
String text = st.nextToken();
node = node.getChildren().computeIfAbsent(text, k -> new TrieNode());
}
node.setEndOfWord(true);
}
}
static class TrieNode {
Map<String, TrieNode> children = new HashMap<String, TrieNode>();
boolean isEndOfWord;
public Map<String, TrieNode> getChildren() {
return children;
}
public void setEndOfWord(boolean endOfWord) {
isEndOfWord = endOfWord;
}
public void printNode(int depth) {
StringBuilder branch = new StringBuilder();
for (int i = 0; i < depth; i++) {
branch.append("--");
}
List<String> keySet = new ArrayList<>(children.keySet());
Collections.sort(keySet);
for (String key : keySet) {
System.out.println(branch + key);
children.get(key).printNode(depth + 1);
}
}
}
}
'알고리즘 > 백준' 카테고리의 다른 글
[백준] 1541번 잃어버린 괄호 - 자바 (0) | 2022.10.13 |
---|---|
[백준] 1743번 음식물 피하기 - 자바 (0) | 2022.10.13 |
[백준] 6550번 부분 문자열 - 자바 (0) | 2022.10.09 |
[백준] 3190번 뱀 - 자바 (0) | 2022.10.08 |
[백준] 11399번 ATM - 자바 (1) | 2022.10.07 |