八皇后问题

本文介绍了N皇后问题的两种解决方法。一种利用C++11特性如lambda表达式和范围for循环来简化代码,另一种则采用递归与回溯的方式,并详细解释了如何通过检查行列及对角线来判断皇后间是否会产生冲突。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

方案一

  说的有点夸装,实际上并不只是八行代码,加上前面的变量声明之类的一共有40多行的样子吧,好像是
在知乎上看到的,现在有时间再把它写下来:
  其中用到了一些c++11特性,例如lambda 以及给予范围的 for循环。
  其他的没什么好说的,看代码,上面也有注释的。

复制代码
 1 #include <iostream>
 2 #include <algorithm>
 3 #include <vector>
 4 #include <set>
 5 using namespace std;
 6 void eightQueen(int n);
 7 int main()
 8 {
 9     eightQueen(8);
10     system("pause");
11     return 0;
12 }
13 
14 void eightQueen(int n)
15 {
16     int count = 0;
17     vector<int> border(n);
18     for (int i = 0; i < n; ++i)
19         border[i] = i + 1;    //这一步就决定了每一行的上下左右都不会有其他的皇后
20     vector<int> afterAdd(8);
21     vector<int> afterSub(8);
22     for(;;){
23         transform(border.begin(), border.end(), afterAdd.begin(), 
24             [](int i)->int{static int index = 1; i += index; index++; return i; });
25         transform(border.begin(), border.end(), afterSub.begin(), 
26             [](int i)->int{static int index = 1; i -= index; index++; return i; });
27         set<int> afterAddSet(afterAdd.begin(), afterAdd.end());
28         set<int> afterSubSet(afterSub.begin(), afterSub.end());
29         if (afterAddSet.size() == 8 && afterSubSet.size() == 8){    //如果斜对角线上都没有元素话
30             ++count;
31             for (auto c : border)
32                 cout << c << ' ';
33             cout << endl;
34         }
35         if (!next_permutation(border.begin(), border.end())){
36             cout << "Total : " << count << endl;
37             break;
38         }
39     }
40 }
复制代码

嗯大概就是这样,下面是结果:

复制代码
1 5 8 6 3 7 2 4 
1 6 8 3 7 4 2 5 
1 7 4 6 8 2 5 3 
1 7 5 8 2 4 6 3 
2 4 6 8 3 1 7 5 
2 5 7 1 3 8 6 4 
2 5 7 4 1 8 6 3 
2 6 1 7 4 8 3 5 
2 6 8 3 1 4 7 5 
2 7 3 6 8 5 1 4 
2 7 5 8 1 4 6 3 
2 8 6 1 3 5 7 4 
3 1 7 5 8 2 4 6 
3 5 2 8 1 7 4 6 
3 5 2 8 6 4 7 1 
3 5 7 1 4 2 8 6 
3 5 8 4 1 7 2 6 
3 6 2 5 8 1 7 4 
3 6 2 7 1 4 8 5 
3 6 2 7 5 1 8 4 
3 6 4 1 8 5 7 2 
3 6 4 2 8 5 7 1 
3 6 8 1 4 7 5 2 
3 6 8 1 5 7 2 4 
3 6 8 2 4 1 7 5 
3 7 2 8 5 1 4 6 
3 7 2 8 6 4 1 5 
3 8 4 7 1 6 2 5 
4 1 5 8 2 7 3 6 
4 1 5 8 6 3 7 2 
4 2 5 8 6 1 3 7 
4 2 7 3 6 8 1 5 
4 2 7 3 6 8 5 1 
4 2 7 5 1 8 6 3 
4 2 8 5 7 1 3 6 
4 2 8 6 1 3 5 7 
4 6 1 5 2 8 3 7 
4 6 8 2 7 1 3 5 
4 6 8 3 1 7 5 2 
4 7 1 8 5 2 6 3 
4 7 3 8 2 5 1 6 
4 7 5 2 6 1 3 8 
4 7 5 3 1 6 8 2 
4 8 1 3 6 2 7 5 
4 8 1 5 7 2 6 3 
4 8 5 3 1 7 2 6 
5 1 4 6 8 2 7 3 
5 1 8 4 2 7 3 6 
5 1 8 6 3 7 2 4 
5 2 4 6 8 3 1 7 
5 2 4 7 3 8 6 1 
5 2 6 1 7 4 8 3 
5 2 8 1 4 7 3 6 
5 3 1 6 8 2 4 7 
5 3 1 7 2 8 6 4 
5 3 8 4 7 1 6 2 
5 7 1 3 8 6 4 2 
5 7 1 4 2 8 6 3 
5 7 2 4 8 1 3 6 
5 7 2 6 3 1 4 8 
5 7 2 6 3 1 8 4 
5 7 4 1 3 8 6 2 
5 8 4 1 3 6 2 7 
5 8 4 1 7 2 6 3 
6 1 5 2 8 3 7 4 
6 2 7 1 3 5 8 4 
6 2 7 1 4 8 5 3 
6 3 1 7 5 8 2 4 
6 3 1 8 4 2 7 5 
6 3 1 8 5 2 4 7 
6 3 5 7 1 4 2 8 
6 3 5 8 1 4 2 7 
6 3 7 2 4 8 1 5 
6 3 7 2 8 5 1 4 
6 3 7 4 1 8 2 5 
6 4 1 5 8 2 7 3 
6 4 2 8 5 7 1 3 
6 4 7 1 3 5 2 8 
6 4 7 1 8 2 5 3 
6 8 2 4 1 7 5 3 
7 1 3 8 6 4 2 5 
7 2 4 1 8 5 3 6 
7 2 6 3 1 4 8 5 
7 3 1 6 8 5 2 4 
7 3 8 2 5 1 6 4 
7 4 2 5 8 1 3 6 
7 4 2 8 6 1 3 5 
7 5 3 1 6 8 2 4 
8 2 4 1 7 5 3 6 
8 2 5 3 1 7 4 6 
8 3 1 6 2 5 7 4 
8 4 1 3 6 2 7 5 
Total : 92
复制代码

一共有92种方式,由于是枚举了所有的可能情况,所以用时稍微有一点长。

http://www.cnblogs.com/-wang-cheng/p/4854484.html

###方案二

1问题描述
N皇后问题,就是如何将国际象棋中的N个皇后放在N*N的棋盘上而不会互相攻击,是一种通过枚举,再递归、回溯的思想。

2思路
以8皇后问题为例,可知在8*8二维数组中,每个点用data[i][j]表示(0 <= i,j <= 7)。
其中其主对角线上(左上到右下)的每个点的i-j+7的值都相同(范围0-14)。
其从对角线上(右上到左下)的每个点i+j的值都相同(返回0-14)。
且其中每个子方阵的主对角线之间的i-j+7的值都不同,从对角线之间的i+j的值也不同。
如在4*4的子方阵中的data[3][4]:
穿过data[3][4]的主对角线:3-4+7=6
穿过data[3][4]的从对角线:3+4=7
若是穿过data[4][4],其主对角线:4-4+7=7;从对角线:4+4=8
为何要研究这种规律呢?

因为摆放皇后时,可知N个皇后肯定在不同行,不同列,以及不同对角线上。因此每在一个不同行摆放一个皇后时,首先要检查该列是不是被占用,以及穿过该点的主、从对角线是否被占用,若是则要换列。

3具体代码

bool checkCol[]:表示每一列的占用情况,大小1*N
bool leftCross[]:表示穿过该放置点(i,j)的主对角线的占用情况,其下标为i-j+7。
bool rightCross[]:表示穿过该放置点(i,j)的从对角线的占用情况,下标为i+j。
int * *data:N*N棋盘。

#include <iostream>
#include <stdlib.h>
#include <stdio.h>
using namespace std;

int count_Method = 0;
int queenNum = 0;
bool *checkCol;
bool *leftCross;
bool *rightCross;
int **data;

void getNQueens( int );


/*
功能: 求解放置8皇后方案的个数。
输入:N个皇后个数
无
返回:
int:放置8皇后方案的个数
*/

int PlaceQueenMethodNum(int N)
{
    /*在这里实现功能*/
    queenNum = N;
    data = (int **)malloc(N*sizeof(int*));
    for(int i = 0; i < N; i++){
        data[i] = (int *)malloc(N*sizeof(int));
    }
    checkCol = (bool *)malloc(N*sizeof(bool));   //column(列)占用情况,占用为true,反之false
    leftCross = (bool *)malloc((2*N-1)*sizeof(bool));//左对角线
    rightCross = (bool *)malloc((2*N-1)*sizeof(bool));//右对角线情况
    for(int i = 0; i < 2*N-1; i++ ) //主、从对角线
        leftCross[i] = rightCross[i] = false; //表示安全

    for(int i = 0; i < N; i++ )//chess
    {
        checkCol[i] = false;
        for(int j = 0; j < N; j++ ){
            data[i][j] = 0;
        }
    }

    getNQueens( 0 );

    return count_Method;
}

void getNQueens( int row )
{
    if( row == queenNum )//N个皇后安置就位,解决方案+1
    {
        count_Method++;
        return;
    }

    for( int column = 0; column < queenNum; column++ )
    {
        if( !checkCol[column] && leftCross[row-column+7] == false && rightCross[row+column] == false )
        {
            data[row][column] = 1; 
            //安置皇后
            checkCol[column] = true;   //此列被占
            leftCross[row-column+7] = true; //主对角线被占
            rightCross[row+column] = true;  //从对角线被占
            getNQueens(row+1); //下一个皇后
            //此步重置,列右移继续找
            data[row][column] = 0;
            checkCol[column] = false; 
            leftCross[row-column+7] = false;
            rightCross[row+column] = false;
        }
    }
}

int main(){
    int n;
    cin>>n;
    cout<<PlaceQueenMethodNum(n);
    system("pause");
}

http://blog.youkuaiyun.com/chenloxiaoea/article/details/50246523

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值