-
[백준] 1062번 가르침 (by Python)Programming/Algorithm 2021. 3. 24. 17:13
문제
https://www.acmicpc.net/problem/1062
풀이
브루트 포스 방식으로 푸는 비트마스킹 문제이다. 처음에는 비트마스킹 방식이 익숙하지 않아서 set으로 시도해봤으나 시간 초과의 벽에 막혀 비트마스킹 방법으로 풀게 되었다.
import sys from itertools import combinations input = sys.stdin.readline def convert(x): return ord(x) - ord('a') def convert_2(arr): result = 0 for a in arr: result |= (1 << a) return result n, k = map(int, input().split()) s = set([convert(a) for a in ['a', 'c', 'i', 'n', 't']]) base = 0 for i in s: base |= (1 << i) arr = [set(map(convert, input().strip())) for _ in range(n)] arr_2 = [convert_2(a) for a in arr] candidates = set().union(*arr) - s answer = 0 if k < 5: print(0) else: if len(candidates) <= (k - 5): print(n) else: for c in combinations(candidates, k - 5): temp = base for i in c: temp |= (1 << i) temp ^= (1 << 26) - 1 answer = max(answer, sum(1 if (temp & a) == 0 else 0 for a in arr_2)) print(answer)
기본적으로 모든 단어에 포함되어있는 'antatica'에 있는 알파벳 집합 {'a', 'c', 'i', 'n', 't'} 를 가지고 있는 수를 비트마스킹을 통해 표현한다. 단어는 모두 영어 소문자로 표현되어있다는 것이 명시되어 있으므로, 'a'부터 'z'까지를 각각 0~25의 수에 mapping 후 비트연산을 해주어 base를 만든다. 만약 k가 5보다 작을 경우 base에 있는 알파벳들을 모두 포함하는 것이 불가능하므로 자연스럽게 답은 0이 된다.
카운트를 하기 위해 각 단어마다 추가적으로 필요한 알파벳을 비트마스킹된 형태로 저장하는 리스트 arr_2와 고를 수 있는 알파벳 후보군이 모두 담긴 집합 candidates를 둔다. 만약 candidates의 원소 개수가 (k - 5)보다 작거나 같을 경우, 모든 단어를 알 수 있을 만큼 충분한 알파벳을 가르칠 수 있다는 뜻이기에 답은 n이다. 예외처리를 해주지 않을 경우, combinations 라이브러리는 이런 경우에 그냥 지나가므로 주의해야 한다. 그 외의 경우, candidates에서 (k - 5)개의 알파벳 조합들 중 어느 것이 가장 많은 단어를 표현할 수 있는지 세면 되는 방식이다.
개인적으로 list에 포함된 set들을 한꺼번에 union하는 방법을 배우고, 비트마스킹에서 포함관계를 비교하는 식 (XOR 후 AND 비교)을 알게 돼서 많이 배운 문제였다.
'Programming > Algorithm' 카테고리의 다른 글
[백준] 14719번 빗물 (by Python) (0) 2021.03.26 [백준] 1786번 찾기 (by Python) (0) 2021.03.24 [백준] 18404번 현명한 나이트 (by Python) (0) 2021.03.14 [백준] 18310번 안테나 (by Python) (0) 2021.03.14 [백준] 3665번 최종 순위 (by Python) (0) 2021.03.14