n皇后问题[分支限界法]


问题:
  如何能够在 n×n 的国际象棋棋盘上放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行、纵行或斜线上。

分析:
  我们可以用一串数字来表示问题的解,比如[2,4,1,3] 表示 4×4 棋盘的4皇后问题的解,第一行的棋子摆在第2列;第二行的棋子摆在第4列,依此类推
  这里将用回溯法进行解题,可以看出,某一行的棋子摆了之后,棋子的那一列肯定不能再摆其他的棋子了,

  所以解[x,x,x,……,x] 一定是 1-n 的一个全排列,

  所以这里的解空间树我们选择排列树。


思路:
  既然已经确定了要用排列树来作为问题的解空间树,接下来要确定的就是剪枝函数了。

  剪枝函数只要从已经摆好的棋子的第一个开始遍历,依此判断下面的棋子是否在其攻击范围内即可,

  因为我们之前没有在同一行摆多个棋子,也没有在同一列摆多个棋子,所以只要判断其他棋子是否在其斜线上的攻击范围即可,比如

      

  第一行的棋子摆在第3列上,只要沿图中方向判断即可

    

for (int i = 1; i <= n-1; i++) { for (int j = i + 1; j <= n; j++) { int left = -(j - i);//向左的斜线
            int right = (j - i);//向右的斜线
            if (pieces[j] == pieces[i] + left||pieces[j] == pieces[i] + right) {//第i行皇后和第j行皇后会互相攻击
                return false; } } }

代码:

  这样摆好所有棋子后即可输出,代码如下:

  

#include<iostream> #include<ctime>
using namespace std; bool isOK(int n, int pieces[]) { //剪枝函数 //判断当前状态是否合理,即皇后会不会互相攻击
    for (int i = 1; i <= n-1; i++) { for (int j = i + 1; j <= n; j++) { int left = -(j - i);//向左的斜线
            int right = (j - i);//向右的斜线
            if (pieces[j] == pieces[i] + left||pieces[j] == pieces[i] + right) {//第i行皇后和第j行皇后会互相攻击
                return false; } } } //所有皇后都不会互相攻击
    return true; } void swap(int &a, int &b) { int t = a; a = b; b = t; } void nQueen(int n, int t, int pieces[]) { if (t > n) { for (int i = 1; i <= n; i++) { for (int j = 1; j < pieces[i]; j++) cout << "- "; cout << pieces[i]<<" "; for (int j = pieces[i] + 1; j <= n; j++) cout << "- "; cout << endl; } cout << endl; } else { for (int i = t; i <= n; i++) { swap(pieces[t], pieces[i]); if (isOK(t, pieces)) { nQueen(n, t + 1, pieces); } swap(pieces[t], pieces[i]); } } } void main() { int n; cin >> n; int *pieces = new int[n + 1]; for (int i = 1; i <= n; i++) { pieces[i] = i; } nQueen(n, 1, pieces); cout << "OK" << endl; system("pause"); }

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM