经典皇后问题

 

题目描述:编写一个程序求解皇后问题:在n×n的方格棋盘上,放置n个皇后,要求每个皇后不同行、不同列、不同左右对角线。

 

解法一:递归算法

 

设f(i,n)表示在n×n的方格棋盘上,已放置好第1个,...,第i-1个皇后,现要放置第i个,...,第n个皇后。放置前i个皇后的解法f(i,n)和放置前i+1个皇后的解法f(i+1,n)是相似的。求解皇后问题的递归模型如下。

①f(i,n):若i=n,则n个皇后放置完毕,输出解。

②f(k,n):在第k列上找到合适的位置放置一个皇后,f(k+1,n)。

 

接下来问题的关键是如果找到这个合适的位置,使得每个皇后不同行、不同列、不同左右对角线。

①显然不同列是成立的。因为前面k-1个皇后分别放置在1~k-1列,而该皇后则放在k列上。

②假设前面第j(1<=j<=k-1)个皇后,放置在位置为(q[j],j)的方格上,其中q[j]为行,j为列。则要求与(i,k)位置的皇后不同行的条件为:q[j]!=i;

③先来看一下图1:

图一

 

我们会发现一个简单的规律:即同一条对角线上的由左上方到右下方的每个元素有相同的“行-列”值,1-1=2-2=...=5-5。同样,在同一条对角线上的由右上方到左下方的每个元素则有相同的“行+列”的值,1+5=2+4=...=5+1。然后,根据右图可得到一下结论:当q[j]-j==i-k或则q[j]+j==i+k时,它们才在同一对角线上。两式一项整理得:当且仅当|q[j]-1|==|j-k|时,两个皇后在同一条对角线上。

 

对应的递归算法如下:
void Queens(int k,int n)
{
            if(k==n) 输出第一个解;
            else
                   for(int i=1;i<=n;i++)
                        if(第k列的第i行合适)
                        {
                          在位置处放一个皇后即q[k]=i;
                          Queens(k+1,n);
                         }
}

 

C++实现如下:

 

 

皇后问题(n<20) n:6
皇后问题求解如下:
第1个解:(1,2)(2,4)(3,6)(4,1)(5,3)(6,5)
第2个解:(1,3)(2,6)(3,2)(4,5)(5,1)(6,4)
第3个解:(1,4)(2,1)(3,5)(4,2)(5,6)(6,3)
第4个解:(1,5)(2,3)(3,1)(4,6)(5,4)(6,2)

请按任意键继续. . .

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 这是一个经典的问题,可以使用回溯算法来解决。具体步骤如下: 1. 定义一个n×n的二维数组表示棋盘,初始化为。 2. 从第一开始,依次尝试在每一放置皇后。如果该位置不冲突,则将该位置标记为1,并递归到下一。 3. 如果递归到最后一,说明已经找到了一组解,将该解保存下来。 4. 如果当前无法找到合适的位置放置皇后,则回溯到上一,重新尝试其他。 5. 重复2-4步,直到找到所有解。 需要注意的是,在判断某个位置是否冲突时,需要检查该位置所在的左右对角线是否已经有皇后。可以使用三个一维数组来记录已经占用的对角线。 代码实现可以参考以下示例: ### 回答2: 皇后问题是一道经典的搜索问题,目的是找到在nxn的棋盘放置n个皇后,使得每个皇后都不在同一、同一或同一对角线上。 解决皇后问题的常见方法是回溯法。回溯是一种深度优先搜索,从棋盘的第一开始,依次尝试在每个位置放置皇后,然后递归处理下一。如果无法在第一放置皇后,则回溯到上一重新尝试。在每一个空格中,我们必须检查这个空格是否在同一、同一或同一对角线上的其他任何皇后。如果没有,我们就可以放置皇后,否则就必须回溯到上一个格子。 下面是具体实现思路: 1. 定义一个二维数组board,记录皇后的位置; 2. 定义一个isValid函数,判断当前位置是否可以放置皇后,判断条件包括对角线; 3. 定义一个backtrack函数,从第一开始尝试放置皇后,到最后一时记录一组正确的解; 4. 在backtrack函数中,首先遍历第一的所有位置,然后判断该位置是否可以放置皇后,如果可以,将当前位置赋值为1,继续递归到下一; 5. 递归回溯时,将当前位置重新赋值为0; 6. 返回所有正确解的数组。 代码如下: ``` class Solution: def solveNQueens(self, n: int) -> List[List[str]]: board = [[0] * n for _ in range(n)] res = [] def isValid(row, col): # check column for i in range(row): if board[i][col] == 1: return False # check diagonal for i, j in zip(range(row-1, -1, -1), range(col-1, -1, -1)): if board[i][j] == 1: return False for i, j in zip(range(row-1, -1, -1), range(col+1, n)): if board[i][j] == 1: return False return True def backtrack(row): if row == n: tmp = [] for i in range(n): s = "" for j in range(n): if board[i][j] == 1: s += "Q" else: s += "." tmp.append(s) res.append(tmp) return for col in range(n): if isValid(row, col): board[row][col] = 1 backtrack(row+1) board[row][col] = 0 backtrack(0) return res ``` 以上代码中,isValid函数用于判断当前位置是否可以放置皇后,backtrack函数用于回溯处理,最后返回所有的正确解。该思路是一种非常经典的排组合问题解决方法,值得学习掌握。 ### 回答3: 题目要求在$n\times n$的方格棋盘放置$n$个皇后要求每个皇后不同不同不同左右对角线。这个问题可以通过递归和回溯的方法来解决,即先放置第一个皇后,然后逐递归,对于每一,依次判断每一是否可以放置皇后,如果可以放置,就继续递归下一,否则回溯到上一,换一个位置重试,直到找到合适的位置或者回溯到第一。 具体实现如下: 1.定义一个数组$pos$,$pos[i]$表示第$i$皇后在哪一。初始值为$-1$,表示还没有放置。 2.定义一个函数$check(i,j)$,用来判断在第$i$$j$是否可以放置皇后。这个函数需要依次检查第$1$到第$i-1$,看是否有皇后在同一或者同一对角线。 3.定义一个递归函数$place(row)$,表示在第$row$放置皇后。首先检查是否已经处理完最后一,如果是,说明找到了一组解,输出结果;否则,依次尝试在当前的每一放置皇后,如果找到合适的位置,设置$pos[row]=j$(在第$row$$j$放置皇后),并递归下一$place(row+1)$;如果不,回溯到上一,继续尝试。 4.调用$place(0)$开始递归,求解$n$皇后问题。 代码如下: ``` #include <iostream> #include <cmath> using namespace std; const int MAXN = 100; // 最大棋盘大小 int n; // 棋盘大小 int pos[MAXN]; // pos[i]表示第i皇后所在 // 检查在第ij是否可以放置皇后 bool check(int i, int j) { for (int k = 0; k < i; ++k) { // 同一皇后 if (pos[k] == j) return false; // 同一对角线皇后 if (abs(k - i) == abs(pos[k] - j)) return false; } return true; } // 在第row皇后 void place(int row) { if (row == n) { // 找到一种解 for (int i = 0; i < n; ++i) { for (int j = 0; j < n; ++j) { if (pos[i] == j) cout << "Q "; else cout << ". "; } cout << endl; } cout << endl; return; } for (int i = 0; i < n; ++i) { if (check(row, i)) { pos[row] = i; // 在第rowi放置皇后 place(row + 1); // 递归下一 pos[row] = -1; // 回溯 } } } int main() { cin >> n; // 初始化pos数组 for (int i = 0; i < MAXN; ++i) { pos[i] = -1; } place(0); return 0; } ``` 该程序的时间复杂度为$O(n^n)$,即需要尝试的方案数为$n^n$。因此,当$n$较大时,程序的运时间会非常长,实际应用中需要考虑优化算法

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值