새소식

PS/백준

[백준/2848] 알고스팟어 (Python)

  • -

Problem : https://www.acmicpc.net/problem/2848

 

2848번: 알고스팟어

첫째 줄에 알고스팟어의 알파벳 순서를 출력한다. 만약, 올바른 순서가 없다면 "!"를, 가능한 순서가 두 개 이상이라면 "?"를 출력한다.

www.acmicpc.net

 

Difficulty : Platinum 4

 

Status : Solved

 

Time : 00:52:22

 


 

문제 설명

 

더보기

 

알고스팟어는 알고스팟 커뮤니티에서 사용하는 언어다. 이 언어는 영어 알파벳을 사용하지만, 영어와 알파벳 순서는 다르다.

알고스팟어의 알파벳 사전 순으로 정렬되어 있는 단어의 목록이 주어졌을 때, 알고스팟어의 알파벳 순서를 구하는 프로그램을 작성하시오.

 

 

입력 및 출력

 

더보기

입력

 

첫째 줄에 단어의 개수 N (N ≤ 100)이 주어진다. 다음 N개 줄에는 알고스팟어 단어가 하나씩 주어진다. 단어의 길이는 최대 10이며, 소문자로만 이루어져 있다.

 

출력

 

첫째 줄에 알고스팟어의 알파벳 순서를 출력한다. 만약, 올바른 순서가 없다면 "!"를, 가능한 순서가 두 개 이상이라면 "?"를 출력한다.

 

입력 예시

 

5 ula uka klua kula al

 

출력 예시

 

luka

 

 


 

풀이

 

우선, 다음 두 가지 경우를 생각해 볼 수 있다.

 

  • 사전 순으로 정렬되었다는 전제를 지켰는지
  • 전제가 지켜졌다는 하에, 알파벳 순서를 정확히 구할 수 있는지

 

첫 번째가 지켜지지 않는 엣지 케이스를 보자.

  • aaa - aa는 사전 순 정렬 전제가 부정되어 있다.
  • prefix가 동일할 때('aa', 'aa') 사전 순으로 뒤에 와야 할(길이가 더 긴) 단어가 뒤에 있다면 전제 자체가 무너졌으므로 '!'를 출력해야 한다.

 

두 번째를 보자. 우리는 실제로 인접한 i, i+1번째 단어들만을 검사하면 된다. 각 단어를 검사하여, i번째와 i+1번째가 차이가 나는 지점에서 두 알파벳의 순서가 결정된다.

  • adb - acd 가 존재한다면, 처음으로 차이나는 d - c에서 알파벳의 순서가 결정된다.
  • 즉 이를 indegree, outdegree로 참조하여 위상 정렬을 적용해 볼 수 있다.
  • indegree가 0인 지점들을 모아 위상 정렬을 수행하자. 

 

위상 정렬을 bfs로 수행(khan 알고리즘)할 때, 다음 상황이 등장할 수 있다.

  • 올바른 상황 : 모든 알파벳이 한 그래프 내에 존재하고, 진입 depth가 서로 다른 상황이다. 이 경우는 진입 depth에 따라 정렬하여 출력하면 된다.
  • 올바른 순서가 없는 상황 : 그래프 내에서 사이클이 발견될 때이다. bfs를 수행하며 이미 방문한 이전 노드에 접근할 수 있을때 사이클이 존재한다고 볼 수 있다.
  • 가능한 순서가 두 개 이상인 상황 : 진입 depth가 동일한 알파벳이 두 개 이상 존재한다면, 그 알파벳들의 순서를 가릴 수 없다. 마찬가지로 그래프가 2개 이상인 상황 역시 동일하다.

 

 

풀이 코드

from collections import deque import sys input = sys.stdin.readline N = int(input()) words = [input().strip() for _ in range(N)] word_set = set(''.join(words)) wlen = len(word_set) next_s = { key : [] for key in word_set } required = { key : 0 for key in word_set } visited = { key : -1 for key in word_set } w_visited = set([words[0]]) q = deque() enable = True sortable = True ans = '' for i in range(N-1) : a, b = words[i], words[i+1] if a == b : continue if b in w_visited : enable = False break w_visited.add(b) length = min(len(a), len(b)) flg = False for j in range(length) : if a[j] != b[j] : flg = True break if not flg : if len(a) > len(b) : enable = False break continue required[b[j]] += 1 next_s[a[j]].append(b[j]) for w in word_set : if not required[w] : visited[w] = 0 q.append((w, 0)) while q and enable : w, d = q.popleft() for next_w in next_s[w] : if visited[next_w] > -1 : enable = False break required[next_w] -= 1 if not required[next_w] : visited[next_w] = d+1 q.append((next_w, d+1)) if -1 in visited.values() : enable = False if enable : visited = sorted(visited.items(), key = lambda x : x[1]) for i in range(wlen) : w, d = visited[i] if d != i : sortable = False break ans += w if not enable : print('!') elif not sortable : print('?') else : print(ans)

풀이 완료!

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.