Plite
전자오락 공방
Plite
전체 방문자
오늘
어제
  • 분류 전체보기 (274)
    • 프로젝트 (18)
      • 완성 프로젝트 (3)
      • 프로젝트 진행 내역 (15)
    • 공부 및 정리 (241)
      • 백준 코드 (222)
      • C++ (8)
      • DirectX (2)
      • Unreal Engine (6)
      • 프로그래밍 패턴 (3)
    • 기타 (12)
      • 기타 주저리 (10)
    • 게임과 취미 (1)
    • 대문 (1)

블로그 메뉴

  • 홈
  • 프로젝트
  • 취미, 일상
  • 백준 프로필

공지사항

  • [Read Me]
  • 제 블로그에 방문하신 것을 환영합니다.

인기 글

태그

  • 백준
  • 트리
  • KMP
  • 기하
  • 트라이
  • 세그먼트 트리
  • 백트래킹
  • 동적계획법
  • 정수론
  • 우선순위큐
  • C++
  • 구현
  • 큐
  • 조합론
  • 그래프
  • 투포인터
  • 최소 스패닝 트리
  • LCA
  • UC++
  • 문자열
  • SCC
  • 유니온 파인드
  • 수학
  • 누적합
  • 스택
  • 위상 정렬
  • 브루트포스
  • 이분탐색
  • 분할정복
  • 정렬

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
Plite
공부 및 정리/백준 코드

[C++]백준 - 5670번 문제

[C++]백준 - 5670번 문제
공부 및 정리/백준 코드

[C++]백준 - 5670번 문제

2021. 12. 3. 17:45

5670번: 휴대폰 자판 (acmicpc.net)

 

5670번: 휴대폰 자판

휴대폰에서 길이가 P인 영단어를 입력하려면 버튼을 P번 눌러야 한다. 그러나 시스템프로그래밍 연구실에 근무하는 승혁연구원은 사전을 사용해 이 입력을 더 빨리 할 수 있는 자판 모듈을 개발

www.acmicpc.net

 

5670번 : 휴대폰 자판


휴대폰에서 길이가 P인 영단어를 입력하려면 버튼을 P번 눌러야 한다. 그러나 시스템프로그래밍 연구실에 근무하는 승혁연구원은 사전을 사용해 이 입력을 더 빨리 할 수 있는 자판 모듈을 개발하였다. 이 모듈은 사전 내에서 가능한 다음 글자가 하나뿐이라면 그 글자를 버튼 입력 없이 자동으로 입력해 준다! 자세한 작동 과정을 설명하자면 다음과 같다.

  1. 모듈이 단어의 첫 번째 글자를 추론하지는 않는다. 즉, 사전의 모든 단어가 같은 알파벳으로 시작하더라도 반드시 첫 글자는 사용자가 버튼을 눌러 입력해야 한다.
  2. 길이가 1 이상인 문자열 c1c2...cn이 지금까지 입력되었을 때, 사전 안의 모든 c1c2...cn으로 시작하는 단어가 c1c2...cnc로도 시작하는 글자 c가 존재한다면 모듈은 사용자의 버튼 입력 없이도 자동으로 c를 입력해 준다. 그렇지 않다면 사용자의 입력을 기다린다.

예를 들면, 사전에 "hello", "hell", "heaven", "goodbye" 4개의 단어가 있고 사용자가 "h"를 입력하면 모듈은 자동으로 "e"를 입력해 준다. 사전상의 "h"로 시작하는 단어들은 모두 그 뒤에 "e"가 오기 때문이다. 그러나 단어들 중 "hel"로 시작하는 것도, "hea"로 시작하는 것도 있기 때문에 여기서 모듈은 사용자의 입력을 기다린다. 이어서 사용자가 "l"을 입력하면 모듈은 "l"을 자동으로 입력해 준다. 그러나 여기서 끝나는 단어인 "hell"과 그렇지 않은 단어인 "hello"가 공존하므로 모듈은 다시 입력을 기다린다. 사용자가 "hell"을 입력하기 원한다면 여기서 입력을 멈출 것이고, "hello"를 입력하기 원한다면 직접 "o" 버튼을 눌러서 입력해 줘야 한다. 따라서 "hello"를 입력하려면 사용자는 총 3번 버튼을 눌러야 하고, "hell", "heaven"은 2번이다. "heaven"의 경우 "he"에서 "a"를 입력하면 바로 뒷부분이 모두 자동으로 입력되기 때문이다. 비슷하게, "goodbye"는 단 한 번만 버튼을 눌러도 입력이 완료될 것이다. "g"를 입력하는 순간 뒤에 오는 글자가 항상 유일하므로 끝까지 자동으로 입력되기 때문이다. 이때 사전에 있는 단어들을 입력하기 위해 버튼을 눌러야 하는 횟수의 평균은 (3 + 2 + 2 + 1)/4 = 2.00이다.

사전이 주어졌을 때, 이 모듈을 사용하면서 이와 같이 각 단어를 입력하기 위해 버튼을 눌러야 하는 횟수의 평균을 구하는 프로그램을 작성하시오.

 

입력


입력은 여러 개의 테스트 케이스로 이루어져 있다.

각 테스트 케이스의 첫째 줄에 사전에 속한 단어의 개수 N이 주어지며(1 ≤ N ≤ 105), 이어서 N개의 줄에 1~80글자인 영어 소문자로만 이루어진 단어가 하나씩 주어진다. 이 단어들로 사전이 구성되어 있으며, 똑같은 단어는 두 번 주어지지 않는다. 각 테스트 케이스마다 입력으로 주어지는 단어의 길이 총합은 최대 106이다.

 

 

출력


각 테스트 케이스마다 한 줄에 걸쳐 문제의 정답을 소수점 둘째 자리까지 반올림하여 출력한다.

 

 

 


 

생각해 볼 점


트라이 알고리즘을 활용할 것입니다.

 

다만, 그냥 사용할 경우에는 메모리가 너무 많이 쓰이기 때문에, 단어별로 나누어야합니다.

 

문제에서 설명한 자동완성이 나타나는 만큼 트라이 노드를 설정합니다.

 

예시 입력 : hello, hell, heaven, goodbye

대략 위와 같은 느낌으로 자료구조를 만들면 문제를 풀 수 있습니다.

 

 

코드


#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
using namespace std;

class Trie
{
private:
	string node;
	Trie* children[26];
public:
	Trie(string str);
	void make_trie(string str);
	int count(string str);
};

//생성자
Trie::Trie(string str = "")
{
	node = str;
	memset(children, 0, sizeof(children)); 
}

//트라이 생성
void Trie::make_trie(string str)
{
	if (str.empty()) return;


	int index = str[0] - 97;

	//이미 존재하는 경우
	if (children[index])
	{
		string new_str = children[index]->node;
		int len = min(new_str.size() ,str.size());

		//일치하는 부분 잘라내기
		int r_index = 1;
		for (; r_index < len; r_index++)
		{
			if (str[r_index] != new_str[r_index]) break;
		}
		children[index]->node = str.substr(0, r_index);
		new_str = new_str.substr(r_index);
		str = str.substr(r_index);

		//기존 노드 아래에 새 노드를 삽입
		if (!new_str.empty())
		{
			Trie* rep_child = new Trie(new_str);
			memcpy(rep_child->children, children[index]->children, sizeof(children));
			memset(children[index]->children, 0, sizeof(children));
			children[index]->children[new_str[0] - 97] = rep_child;
		}

		children[index]->make_trie(str);
		return;
	}

	Trie* new_child = new Trie(str);
	children[index] = new_child;
	str.clear();
	
	new_child->make_trie(str);
}

//str을 치기위해 몇회 자판을 치는 지 반환하는 함수
int Trie::count(string str)
{
	if (str.empty()) return 0;
	int index = str[0] - 97;

	string cmp_str = children[index]->node;
	int len = cmp_str.size();

	//일치하는 부분 잘라내기
	int r_index = 1;
	for (; r_index < len; r_index++)
	{
		if (str[r_index] != cmp_str[r_index]) break;
	}
	str = str.substr(r_index);

	return 1 + children[index]->count(str);
}

int main()
{
	ios::sync_with_stdio(NULL);
	cin.tie(NULL);
	int N;
	while (cin >> N)
	{
		string* arr = new string[N];
		Trie root = Trie();
		for (int i = 0; i < N; i++)
		{
			cin >> arr[i];
			root.make_trie(arr[i]);
		}

		int summ = 0;
		for (int i = 0; i < N; i++) summ += root.count(arr[i]);

		float ans = round((float)summ * 100/ N) / 100;

		
		printf("%.2lf\n", ans);
	}
}

 

그 외


 

저작자표시 (새창열림)

'공부 및 정리 > 백준 코드' 카테고리의 다른 글

[C++]백준 - 4600번 문제  (0) 2021.12.06
[C++]백준 - 2467번 문제  (0) 2021.12.04
[C++]백준 - 16637번 문제  (0) 2021.12.03
[C++]백준 - 1086번 문제  (0) 2021.12.02
[C++]백준 - 9095번 문제  (0) 2021.12.02
  • 5670번 : 휴대폰 자판
  • 입력
  • 출력
  • 생각해 볼 점
  • 코드
  • 그 외
'공부 및 정리/백준 코드' 카테고리의 다른 글
  • [C++]백준 - 4600번 문제
  • [C++]백준 - 2467번 문제
  • [C++]백준 - 16637번 문제
  • [C++]백준 - 1086번 문제
Plite
Plite
개발 일지, 게임 이야기 등을 적어두는 공간입니다.

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.