方案一
说的有点夸装,实际上并不只是八行代码,加上前面的变量声明之类的一共有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