Lançado · em melhoria
Guia de Backtracking · 5/6
Por enquanto, este capítulo está disponível apenas em inglês.
Backtracking problems look different on the surface, but once you decide what counts as one step and when to prune, most of them fit the same template. Try the four problems below on your own first, then compare your approach with the one given.
Given an integer n, list every valid string made of n opening and n closing parentheses. For n = 2 the answer is (()) and ()().
Approach: append one character at a time. An opening parenthesis is allowed only while fewer than n have been used, and a closing one only while fewer have been closed than opened. These two rules are the pruning that prevents invalid strings from ever being built.
def parentheses(n):
out = []
def dfs(s, opened, closed):
if len(s) == 2 * n:
out.append(s)
return
if opened < n:
dfs(s + "(", opened + 1, closed)
if closed < opened:
dfs(s + ")", opened, closed + 1)
dfs("", 0, 0)
return out
print(parentheses(3))
# ['((()))', '(()())', '(())()', '()(())', '()()()']You are given a 2D grid of letters and a word. Decide whether the word can be spelled by moving between horizontally or vertically adjacent cells, using each cell at most once.
Approach: start a search from every cell. Mark the current cell as in use by overwriting it with # (choose), look for the next letter in four directions (explore), then restore the original letter (unchoose). Return immediately when a letter does not match.
def exists(grid, word):
rows, cols = len(grid), len(grid[0])
def dfs(r, c, i):
if i == len(word):
return True
if not (0 <= r < rows and 0 <= c < cols) or grid[r][c] != word[i]:
return False
saved, grid[r][c] = grid[r][c], "#"
found = any(dfs(r + dr, c + dc, i + 1)
for dr, dc in ((1, 0), (-1, 0), (0, 1), (0, -1)))
grid[r][c] = saved
return found
return any(dfs(r, c, 0) for r in range(rows) for c in range(cols))
board = [list("CAT"), list("OXD"), list("DEN")]
print(exists(board, "CODE"), exists(board, "COAT")) # True FalseList the distinct permutations of a list that contains repeated values, such as [1, 1, 2]. No permutation may appear twice in the output.
Approach: sort first. Picking the same value twice at the same depth repeats an identical branch, so skip a value when the equal value right before it has not been used yet. This shrinks the search itself, which is better than generating duplicates and removing them with a set.
def unique_permutations(nums):
nums = sorted(nums)
used = [False] * len(nums)
result, path = [], []
def dfs():
if len(path) == len(nums):
result.append(path[:])
return
for i in range(len(nums)):
if used[i]:
continue
if i > 0 and nums[i] == nums[i - 1] and not used[i - 1]:
continue
used[i] = True
path.append(nums[i])
dfs()
path.pop()
used[i] = False
dfs()
return result
print(unique_permutations([1, 1, 2])) # [[1, 1, 2], [1, 2, 1], [2, 1, 1]]Fill in a 9x9 Sudoku board where empty cells are marked with 0. Assume the puzzle has a solution.
Approach: keep a set of used digits for each row, column, and box so each constraint check is O(1). Fill the empty cells in order; when no digit fits, return False so the previous cell tries its next digit. Once a solution is found, pass True upward so nothing gets undone.
def solve_sudoku(board):
rows = [set() for _ in range(9)]
cols = [set() for _ in range(9)]
boxes = [set() for _ in range(9)]
empty = []
for r in range(9):
for c in range(9):
d = board[r][c]
if d:
rows[r].add(d); cols[c].add(d); boxes[r // 3 * 3 + c // 3].add(d)
else:
empty.append((r, c))
def fill(k):
if k == len(empty):
return True
r, c = empty[k]
b = r // 3 * 3 + c // 3
for d in range(1, 10):
if d in rows[r] or d in cols[c] or d in boxes[b]:
continue
board[r][c] = d
rows[r].add(d); cols[c].add(d); boxes[b].add(d)
if fill(k + 1):
return True
rows[r].remove(d); cols[c].remove(d); boxes[b].remove(d)
board[r][c] = 0
return False
return fill(0)To make it faster, always fill the remaining cell with the fewest candidates next (MRV). On hard puzzles this cuts the number of visited nodes dramatically.
True to end the search early.
0 comentários
Fazer login · Faça login para deixar um comentário.
Seja o primeiro a comentar.