[SCOI2005] 骑士精神

GitHub跳转原题关系图返回列表

以错位非空棋子数为估价函数,在深度 15 内做 IDA*。

OJ: luogu

题目 ID: P2324

难度:提高+/省选-

标签:IDA*启发式搜索棋盘python

日期: 2026-07-16 20:10

题意

空位与一个国际象棋骑士步位置交换,求 15 步内到目标棋盘的最少步数。

思路

逐步增加深度上限做 IDA*。一次移动只搬动一个非空棋子,所以当前与目标不同的非空棋子数,是到目标至少还需的步数;若它超过剩余深度立即剪枝。

搜索还禁止立刻把空位换回,并记录同一轮中某状态已拥有的最大剩余深度,避免以更差条件重复搜索。

Python 知识

  • 棋盘保存在 bytearray 中,递归时交换后再换回,避免大量复制。
  • seen.get(state, -1) >= remaining 是带搜索资源的状态支配剪枝。
  • 目标和输入使用 bytes* 的字节值为 42。

代码

python
import sys


target = b"111110111100*110000100000"
moves = [tuple(nr * 5 + nc for dr, dc in ((1, 2), (1, -2), (-1, 2), (-1, -2),
                                          (2, 1), (2, -1), (-2, 1), (-2, -1))
               if 0 <= (nr := i // 5 + dr) < 5 and 0 <= (nc := i % 5 + dc) < 5)
         for i in range(25)]


def solve(start):
    board = bytearray(start)
    blank = board.index(42)

    def heuristic():
        return sum(value != 42 and value != target[i] for i, value in enumerate(board))

    def dfs(blank_position, previous_blank, remaining, seen):
        estimate = heuristic()
        if estimate == 0:
            return True
        if estimate > remaining:
            return False
        state = bytes(board)
        if seen.get(state, -1) >= remaining:
            return False
        seen[state] = remaining
        for other in moves[blank_position]:
            if other == previous_blank:
                continue
            board[blank_position], board[other] = board[other], board[blank_position]
            if dfs(other, blank_position, remaining - 1, seen):
                return True
            board[blank_position], board[other] = board[other], board[blank_position]
        return False

    for limit in range(16):
        if dfs(blank, -1, limit, {}):
            return limit
    return -1


input = sys.stdin.buffer.readline
answers = []
for _ in range(int(input())):
    answers.append(str(solve(b"".join(input().strip() for _ in range(5)))))
print("\n".join(answers))

复杂度

最坏指数级,深度最多 15;空间为当前 DFS 路径和一轮判重表。

总结

IDA* 的关键是可证明不高估的下界;错位棋子数简单但已经足够有效。