Boggle

ํ’€์ด ์ ‘๊ทผ

์ด ๋ฌธ์ œ๋Š” ํŠธ๋ผ์ด ์ž๋ฃŒ๊ตฌ์กฐ๋กœ ํ’€์ดํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ’€์ด๋ฒ• 1(์‹œ๊ฐ„์ดˆ๊ณผ)

  1. ์‚ฌ์ „(dictionary)์˜ ๋‹จ์–ด์— ๋Œ€ํ•ด ํŠธ๋ผ์ด๋ฅผ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค.
  2. DFS ํƒ์ƒ‰
    • ์ง€๊ธˆ๊นŒ์ง€ ๋ฐฉ๋ฌธํ•œ ๋‹จ์–ด์˜ ์ˆœ์„œ๋กœ ๋งŒ๋“ค์–ด์ง„ ๋ฌธ์ž์—ด(l)์ด ํŠธ๋ผ์ด์— ์žˆ๋Š”์ง€ ํ™•์ธ
    • l๋กœ ์‹œ์ž‘ํ•˜๋Š” ๋‹จ์–ด๊ฐ€ ํŠธ๋ผ์ด์— ์—†์œผ๋ฉด DFS ์ข…๋ฃŒ(์ตœ์ ํ™”)
  3. ํŠธ๋ผ์ด์— ์กฐํšŒ๋œ ๋‹จ์–ด ์ €์žฅ

ํŠธ๋ผ์ด ๊ตฌํ˜„

ํŠธ๋ผ์ด๊ฐ€ ๋ญ์ง€?

ํŠธ๋ผ์ด ๊ตฌํ˜„
class TrieNode:
    def __init__(self, character=None):
        self.c = character
        self.children = {}
        self.is_end = False # ์ด ๊ธ€์ž๊ฐ€ ๋งˆ์ง€๋ง‰์ธ ๋ฌธ์ž์—ด์ด ์กด์žฌํ•จ์„ ๋‚˜ํƒ€๋‚ด๋Š” Flag
 
class Trie:
    def __init__(self):
        self.head = TrieNode()
 
    def add(self, string):
        if len(string) == 0:
            return
        current = self.head
        for c in string:
            if c not in current.children:
                current.children[c] = TrieNode(c)
            current = current.children[c]
        current.is_end = True
    
    def search(self, string):
        current = self.head
        for c in string:
            if c not in current.children:
                return False
            current = current.children[c]
        return current.is_end
 
    def is_prefix(self, string):
        current = self.head
        for c in string:
            if c not in current.children:
                return False
            current = current.children[c]
        return True

์ „์—ญ ๋ณ€์ˆ˜์™€ ๋กœ์ง ํ๋ฆ„

dx = [-1, -1, 0, 1, 1, 1, 0, -1]
dy = [0, 1, 1, 1, 0, -1, -1, -1]
board = list() # ์ด์ฐจ์› ๋ฆฌ์ŠคํŠธ
found = set() # ๋ณด๋“œ์—์„œ ๋ฐœ๊ฒฌํ•œ ๋ฌธ์ž์—ด ์ง‘ํ•ฉ
visited = [[False for _ in range(4)] for _ in range(4)]
 
# ๋กœ์ง ํ๋ฆ„
# ํŠธ๋ผ์ด ์ดˆ๊ธฐํ™”
trie = Trie()
for _ in range(int(input())):
    trie.add(input().strip())
input()
 
# ๋ณด๋“œ๋ณ„ ์ •๋‹ต ๊ตฌํ•˜๊ธฐ
n = int(input())
for i in range(n):
    board = [list(input().strip()) for _ in range(4)]
    found = set()
    visited = [[False for _ in range(4)] for _ in range(4)]
    play_game()
    if i != n - 1:
        input()

์ถœ๋ ฅ ๋ฐ์ดํ„ฐ๋ฅผ ๊ตฌํ•˜๋Š” ๋กœ์ง ํ๋ฆ„

def play_game():
    global found
    scores = 0
    find_word() # ํ•ด๋‹น ๋ณด๋“œ์—์„œ ์–ป์„ ์ˆ˜ ์žˆ๋Š” ๋‹จ์–ด ์ฐพ๊ธฐ
    found = list(found) # ์ •๋ ฌ์„ ์œ„ํ•ด ์ง‘ํ•ฉ์„ ๋ฆฌ์ŠคํŠธ๋กœ ๋ณ€ํ™˜
    found.sort(key= lambda w: (-len(w), w))
    
    for word in found:
        scores += get_score(word)
    print(scores, found[0], len(found))
    return

DFS ํƒ์ƒ‰์œผ๋กœ ํŠธ๋ผ์ด ์กฐํšŒ

# DFS
def find(x, y, chars: list): # chars: ํ˜„์žฌ๊นŒ์ง€ ์ˆœ์„œ๋Œ€๋กœ ๋ฐฉ๋ฌธํ•œ ์•ŒํŒŒ๋ฒณ ๋ฆฌ์ŠคํŠธ
    # ๊ธธ์ด ์ดˆ๊ณผ์‹œ
    if len(chars) > 8:
        return
        
    # ์‚ฌ์ „์— ์žˆ๋Š” ๋‹จ์–ด์ธ์ง€ ํ™•์ธ
    target = ''.join(chars)
 
	# ์กด์žฌํ•˜์ง€ ์•Š๋Š” prefix๋ฉด DFS ์ข…๋ฃŒ
    if not trie.is_prefix(target):
        return
 
	# ์กด์žฌํ•˜๋Š” ๋‹จ์–ด ์ €์žฅ
    if trie.search(target):
        found.add(target)
 
    for i in range(8):
        nx, ny = x + dx[i], y + dy[i]
        if is_range(nx, ny) and not visited[nx][ny]:
            visited[nx][ny] = True
            chars.append(board[nx][ny])
            find(nx, ny, chars)
            visited[nx][ny] = False
            chars.pop()
            
    
 
def find_word() -> None:
    for i in range(4):
        for j in range(4):
            visited[i][j] = True
            find(i, j, [board[i][j]])
            visited[i][j] = False
    return

ํ’€์ด๋ฒ•2(ํŠธ๋ผ์ด ์กฐํšŒ ์ตœ์ ํ™”)

๋งค DFS๋งˆ๋‹ค prefix์™€ search๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ด ๋น„ํšจ์œจ์ ์ด๋‹ค.

๊ทธ๋Ÿผ ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ• ๊นŒ? ํŠธ๋ผ์ด ๋…ธ๋“œ์˜ is_end(์ด ๊ธ€์ž๊ฐ€ ๋งˆ์ง€๋ง‰์ธ ๋ฌธ์ž์—ด์ด ์กด์žฌํ•จ์„ ๋‚˜ํƒ€๋‚ด๋Š” Flag) ๋ฅผ ํ™œ์šฉํ•˜๋ฉด ์ตœ์ ํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค.

  1. ๋ฃจํŠธ์—์„œ ํ•ด๋‹น ๊ธ€์ž๋ฅผ ๊ฐ€์ง„ children์ด ์žˆ๋Š”์ง€ ํ™•์ธ
  2. ์žฌ๊ท€: ํ˜„์žฌ ํŠธ๋ผ์ด ๋…ธ๋“œ์—์„œ ๋‹ค์Œ ๊ธ€์ž๋กœ ์ด๋™ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์ธ
    1. ๋งŒ์•ฝ ์ž์‹์ด ์—†์œผ๋ฉด(prefix๊ฐ€ ์•„๋‹ˆ๋ฉด) ํƒ์ƒ‰ ์ข…๋ฃŒ
    2. ํ˜„์žฌ ๋…ธ๋“œ์˜ is_end ๊ฐ€ True์ด๋ฉด, ๋‹จ์–ด ์ €์žฅ

์ตœ์ข… ์ฝ”๋“œ

Boggle Boggle
class TrieNode:
    def __init__(self, character=None):
        self.c = character
        self.children = {}
        self.is_end = False
 
class Trie:
    def __init__(self):
        self.head = TrieNode()
 
    def add(self, string):
        if len(string) == 0:
            return
        current = self.head
        for c in string:
            if c not in current.children:
                current.children[c] = TrieNode(c)
            current = current.children[c]
        current.is_end = True
 
import sys
 
input = sys.stdin.readline
dx = [-1, -1, 0, 1, 1, 1, 0, -1]
dy = [0, 1, 1, 1, 0, -1, -1, -1]
board = list() # ์ด์ฐจ์› ๋ฆฌ์ŠคํŠธ
found = set() # ๋ณด๋“œ์—์„œ ๋ฐœ๊ฒฌํ•œ ๋ฌธ์ž์—ด
visited = [[False for _ in range(4)] for _ in range(4)]
 
def get_score(string: str):
    length = len(string)
    if length <= 2:
        return 0
    elif length <= 4:
        return 1
    elif length == 5:
        return 2
    elif length == 6:
        return 3
    elif length == 7:
        return 5
    return 11
 
def is_range(x, y):
    return 0 <= x < 4 and 0 <= y < 4
 
# DFS
def find(x, y, node, word):
    if node.is_end:
        found.add(word)
 
    # ๊ธธ์ด ์ดˆ๊ณผ์‹œ
    if len(word) >= 8:
        return
 
    for i in range(8):
        nx, ny = x + dx[i], y + dy[i]
        if is_range(nx, ny) and not visited[nx][ny]:
            c = board[nx][ny]
            # ํ•ด๋‹น ๊ธ€์ž๊ฐ€ ์ž์‹ ๋…ธ๋“œ๋กœ ์กด์žฌํ•˜๋ฉด ํƒ์ƒ‰ ์ง„ํ–‰
            if c in node.children:
                visited[nx][ny] = True
                find(nx, ny, node.children[c], word + c)
                visited[nx][ny] = False
            
def find_word() -> None:        
    for i in range(4):
        for j in range(4):
            c = board[i][j]
            # ํ•ด๋‹น ๊ธ€์ž๊ฐ€ ์ž์‹ ๋…ธ๋“œ๋กœ ์กด์žฌํ•˜๋ฉด ํƒ์ƒ‰ ์ง„ํ–‰
            if c in trie.head.children:
                visited[i][j] = True
                find(i, j, trie.head.children[c], c)
                visited[i][j] = False
 
def play_game():
    global found
    scores = 0
    find_word()
    found = list(found)
    found.sort(key= lambda w: (-len(w), w))
    for word in found:
        scores += get_score(word)
    print(scores, found[0], len(found))
 
trie = Trie()
for _ in range(int(input())):
    trie.add(input().strip())
input()
 
n = int(input())
for i in range(n):
    board = [list(input().strip()) for _ in range(4)]
    found = set()
    visited = [[False for _ in range(4)] for _ in range(4)]
    play_game()
    if i != n - 1:
        input()