回溯法——八皇后问题

八皇后问题

在一个8×8的棋盘上放置8个皇后,使得他们不相互攻击。每个皇后的攻击范围是同行同列和同对角线,求出所有解的个数

在这里插入图片描述

在这里插入图片描述

首先简化问题,如果符合要求放满8个皇后,那么肯定保证每一行和每一列有且仅有一个皇后。那么显然问题就变成了如何在一行或者一列放满8皇后。接着就可以转化为求符合要求的8的全排列,那么求全排列我们显然可以用dfs来解决

既然是逐行放置的,那么皇后肯定不会横向攻击,因此只需要检查是否纵向或者斜向攻击即可。那么怎么判断呢?我们可能会想到用一个二维的vis数组来把可攻击的区域全部标记。这样显然时间复杂度有点大。通过紫书的学习,有一个绝妙的利用棋盘坐标性质的方法,我们设每行每列的坐标值均为0-7:

求出每个格子(x,y)的y-x差值,会发现同一主对角线的差值相同

在这里插入图片描述

求出每个格子(x,y)的x+y的和,会发现同一副对角线的和相同

在这里插入图片描述

那么我们由ans==ans[j]判断是否同一列,cur-ans[cur]==j-ans[j]判断是否同一主对角线,cur+ans[cur]==j+ans[j]判断是否同一副对角线:

int ans[1005];
int n,cnt;
void solve(int cur){   //cur初始为0
    if(cur==n) cnt++;     //只要走到这里,已经放满8个皇后就得出一组解
    else for(int i=0;i<n;i++){  //尝试把第cur行放到第i列
        int ok=1;
        ans[cur]=i;  
        for(int j=0;j<cur;j++) //检查是否和前面放过的皇后冲突
        if( ans[cur]==ans[j] || cur-ans[cur]==j-ans[j] || cur+ans[cur]==j+ans[j] ){ ok=0; break; }
        if(ok) solve(cur+1);
    }
}

似乎节点数很难进一步减少了,但是程序效率可以继续提高:引入一个二维数组vis[3][maxn],vis[0][i]标识第i列是否冲突,vis[1][cur+i]标识副对角线是否冲突,鉴于判断y-x差值时可能为负数,那么就再都加上n变成正数,即vis[2][cur-i+n]判断主对角线是否冲突

bool vis[3][1005];
void solve(int cur){
    if(cur==n) cnt++;
    else for(int i=0;i<n;i++){
        if(!vis[0][i] && !vis[1][cur+i] && !vis[2][cur-i+n]){
            vis[0][i]=vis[1][cur+i]=vis[2][cur-i+n]=1;
            solve(cur+1);
            vis[0][i]=vis[1][cur+i]=vis[2][cur-i+n]=0;
        }
    }
}
### 使用Python通过回溯法解决八皇后问题 #### 实现思路 八皇后问题的目标是在8×8的国际象棋棋盘上放置皇后,使得它们互不攻击。这意味着任何两个皇后都不能位于同一行、同一列或同一对角线上[^3]。 为了实现这一目标,可以采用回溯算法来逐步尝试每一种可能的位置组合。如果当前的选择导致冲突,则撤销该选择并尝试其他可能性。这种方法能够有效地遍历所有可行解,并最终找到满足条件的一个或多于一个解。 具体来说,在每一层递归调用中: - 尝试将一个新皇后放在第`row`行中的某一列; - 对于每一个候选位置,检查它是否会与其他已放置好的皇后发生冲突; - 如果当前位置安全,则继续处理下一行(`row+1`);如果不安全则跳过此位置; - 当到达最后一行之后仍然没有遇到冲突时说明找到了一组有效布局; - 反之如果没有更多可用选项可选且回退至前一层继续探索其它路径直到完成整个搜索过程为止。 以下是具体的Python代码实现: ```python def solve_n_queens(n): solutions = [] def is_not_under_attack(row, col, queens): # Check column and diagonals for conflicts with previously placed queens. for r, c in enumerate(queens): if r == row or \ c == col or \ abs(r - row) == abs(c - col): # Diagonal check return False return True def place_queen(row, queens): if row == n: solutions.append(['.' * i + 'Q' + '.' * (n-i-1) for i in queens]) return for col in range(n): if is_not_under_attack(row, col, queens): place_queen(row + 1, queens + [col]) place_queen(0, []) return solutions if __name__ == "__main__": board_size = 8 result = solve_n_queens(board_size) print(f"Found {len(result)} solution(s).") for idx, sol in enumerate(result[:min(len(result), 5)]): # Print up to first five solutions only as an example print(f"\nSolution #{idx + 1}:") for line in sol: print(line) ``` 这段代码定义了一个名为`solve_n_queens()` 的函数用于解决问题。内部有两个辅助函数:一个是用来判断给定坐标是否受到攻击 `is_not_under_attack()`,另一个则是核心逻辑所在的地方——递归地放置皇后 `place_queen()` 。最后部分展示了如何执行这个方法以及打印出一些样例解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值