【问题标题】:Minimum moves of a knight with bishop [closed]骑士与主教的最小移动[关闭]
【发布时间】:2021-10-29 22:19:11
【问题描述】:

问题是一个骑士在 n*n 棋盘中从 A 点到 B 点的最小移动(骑士可以在水平方向移动两步,在垂直方向移动一步,或者在水平方向垂直移动两步)。棋盘上有一个主教沿对角线移动,除非主教死了或位置在 B 点,否则马不能移动到主教威胁的位置。马可以选择杀死主教(如果它处于它可以移动到)并释放所有先前受到威胁的位置。

我在参加的在线评估中得到了这个问题,但在 15 个测试用例中只有 10 个正确。我想我可能需要在队列中的元组中添加一个布尔值,以判断主教是否在最近的步骤中还活着,但为时已晚。

如何修改?

from collections import deque
import math

n = 5
startRow = 0
startCol = 0
endRow = 4
endCol = 3
bishopRow = 3
bishopCol = 0
from collections import deque
import math
#
# Complete the 'moves' function below.
#
# The function is expected to return an INTEGER.
# The function accepts following parameters:
#  1. INTEGER n
#  2. INTEGER startRow
#  3. INTEGER startCol
#  4. INTEGER endRow
#  5. INTEGER endCol
#  6. INTEGER bishopRow
#  7. INTEGER bishopCol
#
def isBishopAlive(n, bishopRow, bishopCol):
    if bishopRow < n and bishopCol < n:
        return True
    else:
        return False
def moves(n, startRow, startCol, endRow, endCol, bishopRow, bishopCol):
    # Write your code here
    x, y = abs(endRow), abs(endCol)
    res = 0
    moves = ((2,1), (1,2), (-1,2), (-2,1), (-2,-1), (-1,-2), (1,-2), (2,-1))
    visited = []
    queue = deque()
    queue.append((startRow, startCol, 0))
    while queue:
        i, j, steps = queue.popleft()
        if i == x and j == y:
            return res + steps
        for di, dj in moves:
            cr = i + di
            cc = j + dj
            if isBishopAlive(n, bishopRow, bishopCol) == True:
                if abs(cr-bishopRow) == abs(cc-bishopCol):
                    if cc != y and cr != x:
                        continue
                if (cr == bishopRow) and (cc == bishopCol):
                    bishopRow, bishopCol = math.inf, math.inf
            if abs(cr) > n-1 or abs(cc) > n-1:
                continue
            if (cr, cc) in visited:
                continue
            if isBishopAlive(n, bishopRow, bishopCol) == True:
                bishop = True
            else:
                bishop = False
            if ((x-i) * di) > 0 or ((y-j) * dj) > 0:
                queue.append([cr, cc, steps+1])
                visited.append((cr, cc))
    return -1    
    

【问题讨论】:

  • 我对你的行 i, j, steps, bishop = current.... 感到困惑。为什么将相同的值分配给jsteps。你不需要在你的州也包括is_bishop_alive吗?
  • 很抱歉这是一个错字。我试图在元组中添加主教的状态,但它一直给我错误,说我缺少参数。我编辑了帖子 - 请查看我的原始代码
  • 当骑士俘虏主教时,您不能只更改bishopRowbishopCol。这意味着在那之后你看到的每一个州,即使是那些主教没有死的州,你都会表现得好像主教已经死了。主教是否被俘虏必须是您保存状态的一部分,就像骑士的位置一样。

标签: python queue depth-first-search


【解决方案1】:

您的代码存在以下问题:

  • 主教永远不会被俘虏,因为当crcc 到达那个方格时,首先将评估if abs(cr-bishopRow) == abs(cc-bishopCol) 条件——并且发现为真——然后是continue

  • 当主教被捕获时,您的代码在查看未捕获主教的其他路径时永远不会将其放回原处。相反,队列中的项目应该包括是否通过捕获主教来实现该状态。

  • visited 列表中的项目不表示访问是否发生在主教还活着的时候。然而这很重要,因为如果你先参观了一个主教还活着的广场,然后在主教被抓获后再次访问,那么第二次访问可能会带来更好的解决方案。因此,在将正方形标记为已访问时,请在元组中包含活动状态。

  • 代码允许将crcc 的负坐标推送到队列中。应该避免这种情况。

  • 这种排除远离目标的动作过于乐观:

    if ((x-i) * di) > 0 or ((y-j) * dj) > 0
    

    以这个棋盘为例,其中“N”是马,“B”是主教,“e”是末端方格:

    ┌───┬───┬───┬───┬───┐
    │   │   │   │   │   │
    ├───┼───┼───┼───┼───┤
    │   │   │   │   │ B │
    ├───┼───┼───┼───┼───┤
    │   │   │ N │   │   │
    ├───┼───┼───┼───┼───┤
    │   │   │   │   │   │
    ├───┼───┼───┼───┼───┤
    │   │   │   │   │ e │
    └───┴───┴───┴───┴───┘
    

    主教必须先被带走,然后骑士必须移到顶行以获得最佳解决方案。

    我建议只删除此条件,否则请确保它不太严格并且永远不会排除最佳路径。

不是问题,但是:

  • res 永远不会被赋值为 0:不需要这个变量
  • bishop 只是设置,但从不读取:不需要这个变量(以及它周围的if...else 块)
  • visited 应该是一个集合而不是一个列表,这样才能有更好的时间复杂度。
  • endRowendCol 永远不会是负数,因此在 xy 中复制它们的绝对值是没有用的。只需使用原始参数变量即可。
  • 当您在将方块放入队列时将它们标记为已访问时,您还应该在进入循环之前对起始方块执行相同的操作。
  • 有一个嵌套的if 指向一个continue。这些if 条件可以使用and 组合成一个if 条件
  • 使用or 可以将同一级别的两个if 条件合并为一个continue 条件continue
  • (cr == bishopRow) 周围的括号不是必需的。
  • 您可以通过在执行移动时检查是否达到目标来节省一些执行时间,而不是等到该移动从队列中弹出。这只是意味着您必须进行初始检查以查看起始位置是否等于结束位置,但这是值得的。

这是一个更正的版本:

def moves(n, startRow, startCol, endRow, endCol, bishopRow, bishopCol):
    if startRow == endRow and startCol == endCol:  # Deal with trivial case
        return 0
    moves = ((2,1), (1,2), (-1,2), (-2,1), (-2,-1), (-1,-2), (1,-2), (2,-1))
    queue = deque()
    queue.append((startRow, startCol, True, 0))  # Include that bishop is alive
    # Let visited be a set. Mark start as visited and include alive-status
    visited = set([(startRow, startCol, True)])
    while queue:
        i, j, alive, steps = queue.popleft()
        for di, dj in moves:
            cr = i + di
            cc = j + dj
            if cr == endRow and cc == endCol:  # When found, don't bother about queuing it
                return steps + 1 # No need for a res variable 
            # Update alive-state, just for current path
            stillalive = alive and (cr != bishopRow or cc != bishopCol)
            # Neither cr/cc should be negative
            if 0 <= cr < n and 0 <= cc < n and (cr, cc, stillalive) not in visited and (
                    not stillalive or abs(cr - bishopRow) != abs(cc - bishopCol)):
                queue.append((cr, cc, stillalive, steps + 1))  # Append alive-status too
                visited.add((cr, cc, stillalive))  # Visited should depend on alive
    return -1

【讨论】:

    猜你喜欢
    • 2021-12-18
    • 2022-01-23
    • 1970-01-01
    • 2017-08-02
    • 2017-05-03
    • 2022-01-17
    • 2023-03-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多