NxN板上无法通过回溯互相攻击的最大骑士数

问题描述 投票:0回答:1

[目前,我正在研究一个我认为非常有趣的问题。问题如下:

Given a chess board with N rows and N columns, 
what is the maximum number of knights you could place on the board 
so that no knight can be attacked by another knight?

[过去,我已经使用回溯解决了soduku问题,我认为我也可以将回溯应用于此类问题。我当前的思考过程是:

1. Check if the current space that I am looking at is free from attack 
2. If the space is free from attack, place a knight and calculate the maximum number of knights 
3. Backtrack, remove the knight, and calculate the maximum number of knights 
4. If the total number after placing the knight is >= the total number after removing the knight, place the knight again 
5. Go to the next space 

我已经写了一些代码,但是,我不确定我是否正确实现了该代码,或者我的逻辑是否正确

GRID_DIMENSION = 3 

def is_safe(board, position): 
    x,y = position 
    if((x-2) >= 0 and (y-1) >= 0 and board[x-2][y-1] == 1):
        return False
    if((x-2) >= 0 and (y+1) < GRID_DIMENSION and board[x-2][y+1] == 1):
        return False
    if((x+2) < GRID_DIMENSION and (y-1) >= 0 and board[x+2][y-1] == 1):
        return False
    if((x+2) < GRID_DIMENSION and (y+1) < GRID_DIMENSION and board[x+2][y+1] == 1):
        return False
    if((x-1) >= 0 and (y-2) >= 0 and board[x-1][y-2] == 1):
        return False
    if((x-1) >= 0 and (y+2) < GRID_DIMENSION and board[x-1][y+2] == 1):
        return False
    if((x+1) < GRID_DIMENSION and (y-2) >= 0 and board[x+1][y-2] == 1):
        return False
    if((x+1) < GRID_DIMENSION and (y+2) < GRID_DIMENSION and board[x+1][y+2] == 1):
        return False
    return True

def count_knights(board): 
    total = 0
    for i in range(GRID_DIMENSION): 
        for j in range(GRID_DIMENSION): 
            if board[i][j] == 1:
                total = total + 1
    return total  

def calc_knights_backtracking(board, i, j):   
    if i < 0 or i >= GRID_DIMENSION: 
        return 
    if j < 0 or j >= GRID_DIMENSION: 
        return 
    # check if the spot is safe from attacks 
    if(is_safe(board, (i,j))): 
        # place a knight and continue to end of board 
        board[i][j] = 1 
        if j+1 < GRID_DIMENSION: 
            calc_knights_backtracking(board, i, j+1)
        else: 
            calc_knights_backtracking(board, i+1, j)
        # get the total number of knights 
        totalPlaced = count_knights(board)
        # remove the knight from (i,j) and go through rest of board
        board[i][j] = 0
        if j+1 < GRID_DIMENSION: 
            calc_knights_backtracking(board, i, j+1)
        else: 
            calc_knights_backtracking(board, i+1, j)
        # get the total number of knights 
        totalUnplaced = count_knights(board)
        # compare the two 
        if totalPlaced >= totalUnplaced: 
            board[i][j] = 1 
    else: 
        if j+1 < GRID_DIMENSION: 
            calc_knights_backtracking(board, i, j+1)
        else: 
            calc_knights_backtracking(board, i+1, j)

board = [[0 for i in range(GRID_DIMENSION)] for j in range(GRID_DIMENSION)]
calc_knights_backtracking(board, 0, 0)

此代码示例未向我返回具有最大骑士数的正确板配置。我在做什么错?

python backtracking chess
1个回答
0
投票

我也在学习回溯,所以我尝试做这个问题。我认为您的流程很好。但这与N-Queens略有不同。对于N皇后,我们只能逐行检查,因为连续只有一个皇后。但是对于Knight,我们可以在同一行中放置多个骑士。因此,我们必须检查网格中的每个条目。这是我的代码:

import itertools

def solveNKnights(n):

    board = [['.']*n for _ in range(n)]
    # all positions of the board
    pos = [p for p in itertools.product(range(n), repeat=2)]
    # index 0 is the number of knights, index 1 is the board
    res = [0, None]
    backtrack(board, pos, res)
    return res


def isValid(board, p):
    # all attack positions
    arr = [(-2, -1), (-1, -2), (1, -2), (2, -1), (-2, 1), (-1, 2), (1, 2), (2, 1)]
    for tup in arr:
        newi = p[0]+tup[0]
        newj = p[1]+tup[1]
        if 0 <= newi < len(board) and 0 <= newj < len(board[0]):
            if board[newi][newj] == 'K': return False
    return True


def backtrack(board, pos, res):

    if len(pos) == 0:
        # count K in the current board
        ks = sum(i.count('K') for i in board)
        res[0] = max(res[0], ks)
        # save the board if it has the maximum K so far
        if res[0] == ks:
            res[1] = [x[:] for x in board]
        return

    for i in range(len(pos)):
        if not isValid(board, pos[i]):
            continue
        board[pos[i][0]][pos[i][1]] = 'K'
        backtrack(board, pos[i+1:], res)
        board[pos[i][0]][pos[i][1]] = '.'


res = solveNKnights(3)
print(res[0])
print(res[1])
© www.soinside.com 2019 - 2024. All rights reserved.