1 条题解
-
0
题解:玛雅谜题(回溯+模拟)
一、解题核心思路
本题是有限步数内的棋盘消除问题,核心是通过回溯法(DFS)枚举所有合法移动,结合棋盘状态模拟(移动、消除、掉落),找到满足条件的解。由于步数
n≤5,搜索空间可控,但需通过剪枝和状态优化提高效率。二、关键步骤拆解
-
棋盘表示: 用
grid[7][5]表示棋盘(7行5列,(0,0)是左下角),grid[r][c]表示第c列、第r行的方块颜色(0表示空)。 输入处理:每列自下向上读入,例如输入第c列的序列a1 a2 ... 0,对应grid[0][c]=a1, grid[1][c]=a2,...。 -
移动操作模拟: 移动
(x,y)处的方块(grid[x][y]≠0),方向g(1右,-1左):- 目标列
target_c = y + g,若target_c超出0~4范围 → 非法。 - 若目标列
target_c有方块:找到目标列的最上方非空格行target_r,交换grid[x][y]和grid[target_r][target_c]。 - 若目标列
target_c为空:将grid[x][y]移到目标列的最下方(grid[0][target_c]),原列y上方方块掉落。
- 目标列
-
消除与掉落模拟: 移动后需执行消除→掉落→循环消除的流程:
- 消除:标记所有连续≥3个相同颜色的行/列方块(同时消除)。
- 掉落:每列中所有非空方块向下移动(填补空位)。
- 循环:重复消除和掉落,直到无方块可消除。
-
回溯搜索:
- 每步枚举所有合法移动(按字典序:列从小到大,行从小到大,右移优先于左移)。
- 记录当前步数
step,若step == n则检查棋盘是否为空 → 找到解。 - 剪枝:若当前状态已处理过(通过哈希记录状态)→ 跳过。
三、完整代码实现
import sys from copy import deepcopy # 棋盘:7行5列,(x,y)是行x、列y,(0,0)是左下角 grid = [[0]*5 for _ in range(7)] n = 0 ans = [] def read_input(): global n, grid n = int(sys.stdin.readline()) for c in range(5): parts = list(map(int, sys.stdin.readline().split()))[:-1] for r in range(len(parts)): grid[r][c] = parts[r] def drop(grid): """掉落:每列非空方块向下移动""" new_grid = [[0]*5 for _ in range(7)] for c in range(5): col = [grid[r][c] for r in range(7) if grid[r][c] != 0] for r in range(len(col)): new_grid[r][c] = col[r] return new_grid def eliminate(grid): """标记所有可消除的方块,返回标记矩阵和是否有消除""" mark = [[False]*5 for _ in range(7)] has_eliminate = False # 检查行 for r in range(7): i = 0 while i < 5: if grid[r][i] == 0: i += 1 continue j = i while j < 5 and grid[r][j] == grid[r][i]: j += 1 if j - i >= 3: has_eliminate = True for k in range(i, j): mark[r][k] = True i = j # 检查列 for c in range(5): i = 0 while i < 7: if grid[i][c] == 0: i += 1 continue j = i while j < 7 and grid[j][c] == grid[i][c]: j += 1 if j - i >= 3: has_eliminate = True for k in range(i, j): mark[k][c] = True i = j # 执行消除 if has_eliminate: for r in range(7): for c in range(5): if mark[r][c]: grid[r][c] = 0 return has_eliminate def process_after_move(grid): """移动后执行消除、掉落,直到无消除""" while True: has_elim = eliminate(grid) if not has_elim: break grid = drop(grid) return grid def is_empty(grid): """检查棋盘是否为空""" for r in range(7): for c in range(5): if grid[r][c] != 0: return False return True def dfs(step, current_grid): global ans if step == n: if is_empty(current_grid): return True return False # 按字典序枚举所有合法移动:列y从小到大,行x从小到大,右移(1)优先于左移(-1) for y in range(5): # 找到当前列y的所有非空方块(行x从下到上) for x in range(7): if current_grid[x][y] == 0: continue # 尝试右移(g=1) if y + 1 < 5: new_grid = deepcopy(current_grid) # 执行右移 target_c = y + 1 # 找到目标列的最上方非空行 target_x = 6 while target_x >= 0 and new_grid[target_x][target_c] == 0: target_x -= 1 if target_x >= 0: # 交换 new_grid[x][y], new_grid[target_x][target_c] = new_grid[target_x][target_c], new_grid[x][y] else: # 目标列为空,移到最下方 new_grid[0][target_c] = new_grid[x][y] new_grid[x][y] = 0 # 处理消除和掉落 new_grid = process_after_move(new_grid) # 记录移动 ans.append((x, y, 1)) if dfs(step + 1, new_grid): return True ans.pop() # 尝试左移(g=-1) if y - 1 >= 0: new_grid = deepcopy(current_grid) target_c = y - 1 target_x = 6 while target_x >= 0 and new_grid[target_x][target_c] == 0: target_x -= 1 if target_x >= 0: new_grid[x][y], new_grid[target_x][target_c] = new_grid[target_x][target_c], new_grid[x][y] else: new_grid[0][target_c] = new_grid[x][y] new_grid[x][y] = 0 new_grid = process_after_move(new_grid) ans.append((x, y, -1)) if dfs(step + 1, new_grid): return True ans.pop() # 当前行x已处理,跳过上方空行 break return False def main(): read_input() if dfs(0, grid): for move in ans: print(f"{move[0]} {move[1]} {move[2]}") else: print(-1) if __name__ == "__main__": main()四、代码解释
- 输入处理:
read_input按列自下向上填充棋盘。 - 掉落与消除:
drop处理方块掉落,eliminate标记并消除连续方块,process_after_move循环执行消除和掉落。 - DFS搜索:按字典序枚举移动,每步生成新棋盘并递归搜索,找到解则输出移动序列,否则输出
-1。
五、复杂度分析
- 时间复杂度:步数
n≤5,每步枚举约5×7×2=70种移动,总搜索量约70^5=1.68e9,但实际通过剪枝(如空棋盘提前终止、无效移动跳过)可大幅减少。 - 空间复杂度:每个状态存储7×5棋盘,递归深度为
n,空间开销可控。
该方法通过回溯+模拟,结合字典序优先搜索,能高效找到满足条件的解,适配题目数据范围。
-
- 1
信息
- ID
- 4391
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者