[Baekjoon,5670] 휴대폰 자판
각 단어들을 트라이로 구현하여 해결하면 된다. 이때 타이핑을 해야하는 순간을 잘 생각해야 한다. 그 시점은 아래와 같다.
- 문장의 첫 글자를 타이핑하는 경우
 - 현재 형성된 문장에서 문자 갈림길이 존재하는 경우
 - 현재 문장이 완성본과 같은데 추가로 단어가 존재하는 경우
 
이를 그림으로 표현하면 아래와 같다. 1번은 주황색, 2번은 녹색, 3번은 하늘색으로 표현하였다.

구현
이와 같은 과정을 코드로 구현하면 아래와 같다. 트리 구조의 각 자식을 $map$을 이용하여 저장하고 있으며 이를 이용하여 자식이 두 개 이상이면 타이핑을 하고 있다. 또한 따로 $terminal$ 변수를 이용하여 현재 노드에서 문자가 완성되는 지 확인할 수 있다. 이를 통해 위 그림의 하늘색 부분을 처리할 수 있다. 주의할 점은 루트에서 자식이 2개 이상인 경우를 추가로 카운트 하지 않아야 하는 것이다.
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <cstring>
#include <map>
using namespace std;
struct TrieNode
{
	map<char, TrieNode*> children;
	bool terminal;
	TrieNode() : terminal(false) {}
	// 트라이에 문자열 key 삽입
	void insert(const char* key)
	{
		if (*key == 0)
			terminal = true;
		else
		{
			// 노드가 없는 경우 생성
			if (children.count(*key) == 0)
				children[*key] = new TrieNode();
			children[*key]->insert(key + 1);
		}
	}
	int needed_typing(const char* key)
	{
		if (*key == 0) return 0;
		int typing = 0;
		// 문자가 2개로 갈리거나 현재 문자로 끝나는 단어가 있을 경우 
		if (children.size()>1 || terminal)
			++typing;
		return typing + children[*key]->needed_typing(key + 1);
	}
};
int main()
{
	int n;
	while (scanf("%d", &n) != EOF)
	{
		vector<string> words;
		TrieNode* trie = new TrieNode();
		for (int i = 0;i < n;++i)
		{
			char str[82];
			scanf("%s", str);
			// 끝에 한 글자 추가
			string s = str;
			//cout<<s<<endl;
			words.push_back(s);
			trie->insert(str);
		}
		int ret = 0;
		for (int i = 0;i < n;++i)
			// 해당 단어의 시작 문자에서 바로 시작 
			ret += 1 + trie->children[words[i][0]]->needed_typing(words[i].c_str() + 1);
		printf("%.2f \n", (double)ret / n);
		//cout << ret << endl << endl;
	}
	return 0;
}
      
댓글남기기