八皇后问题简介:
八皇后是一道很具典型性的题目。它的基本要求是这样的:在一个8*8的矩阵上面放置8个物体,一个矩阵点只允许放置一个物体,任意两个点不能在一行上,也不能在一列上,不能在一条左斜线上,当然也不能在一条右斜线上。
初看到这道题目,大家的第一印象是遍历,但是经过实践之后发现遍历其实不好写,而且复杂度很低。不仅需要遍历8*8*8*8*8*8*8*8*8 = 2^24次数据,还要判断各种条件,实际的计算复杂度还要比较这个高。其实我们仔细看一看,这中间很多的计算其实很多是不需要的,因为如果我们在某一行没有可以插入的数据的话,那么这后面的行其实就不用考虑了。也就是说,我们只有在保证前面 插入的物体都合法有效的情况下,才能进行下一次的物体插入。无谓的遍历只会是无用功。
那么,我们应该怎么做呢?其实步骤不太难:
(1)在第n行寻找可以插入的位置,中间涉及到位置合法性的判断
(2)如果没有可以插入的位置,返回
(3)如果有可以插入的位置, 插入数据。此时再判断是否已经是最后一行,如果是,打印输出返回;反之继续对下一行数据进行试探处理。
代码如下:
八皇后是一道很具典型性的题目。它的基本要求是这样的:在一个8*8的矩阵上面放置8个物体,一个矩阵点只允许放置一个物体,任意两个点不能在一行上,也不能在一列上,不能在一条左斜线上,当然也不能在一条右斜线上。
初看到这道题目,大家的第一印象是遍历,但是经过实践之后发现遍历其实不好写,而且复杂度很低。不仅需要遍历8*8*8*8*8*8*8*8*8 = 2^24次数据,还要判断各种条件,实际的计算复杂度还要比较这个高。其实我们仔细看一看,这中间很多的计算其实很多是不需要的,因为如果我们在某一行没有可以插入的数据的话,那么这后面的行其实就不用考虑了。也就是说,我们只有在保证前面 插入的物体都合法有效的情况下,才能进行下一次的物体插入。无谓的遍历只会是无用功。
那么,我们应该怎么做呢?其实步骤不太难:
(1)在第n行寻找可以插入的位置,中间涉及到位置合法性的判断
(2)如果没有可以插入的位置,返回
(3)如果有可以插入的位置, 插入数据。此时再判断是否已经是最后一行,如果是,打印输出返回;反之继续对下一行数据进行试探处理。
代码如下:
#include<iostream>
using namespace std;
#define LEN 8
int amount = 0; // 总共棋盘数
bool IsNoDanger(int row, int k, int(*chess)[LEN])
{
int i, j;
// 判断列方向
for (i=0;i<LEN;i++)
{
if (chess[i][k]==1) // 如果某行的某一列这个位置出现皇后,则处于危险状态,退出
{
return false;
}
}
// 判断左上方
for (i = row, j = k; i >= 0 && j >= 0; i--, j--)
{
if (chess[i][j]==1)
{
return false;
}
}
// 判断右下方
for (i=row,j=k;i<LEN&&j<LEN;i++,j++)
{
if (chess[i][j]==1)
{
return false;
}
}
// 判断右上方
for (i=row,j=k;i>=0&&j<LEN;i--,j++)
{
if (chess[i][j]==1)
{
return false;
}
}
// 判断左下方
for (i=row,j=k;i<LEN&&j>=0;i++,j--)
{
if (chess[i][j]==1)
{
return false;
}
}
return true;
}
// row 代表起始行 clo 表示列数 (*chess)[LEN] 指向棋盘每一行的指针
void EightQueue(int row,int clo,int (*chess)[LEN])
{
int chess2[LEN][LEN]; // 创建临时棋盘存放当前的棋盘
int i, j;
// 赋值原棋盘
for (i=0;i<LEN;i++)
{
for (j=0;j<LEN;j++)
{
chess2[i][j] = chess[i][j];
}
}
if (row==LEN) // 如果起始行==LEN,即 row==8 时,打印出棋盘
{
amount++;
cout << "第"<<amount<<"种:"<< endl;
for(i=0;i<LEN;i++)
{
for (j=0;j<LEN;j++)
{
cout << chess2[i][j] << " ";
}
cout << endl;
}
}
else
{
// 判断这个位置是否有危险,如果有危险,则进行继续往下
for (j=0;j<clo;j++)
{
if (IsNoDanger(row, j, chess)) // 判断是否有危险
{
for (i = 0; i < LEN; i++)
chess2[row][i] = 0; // 没有危险,标记为0
chess2[row][j] = 1; // 有危险,标记为1
EightQueue(row + 1, clo, chess2);
}
}
}
}
int main(void)
{
int chess[LEN][LEN] = { 0 }; // 初始化棋盘为0
EightQueue(0,LEN, chess);
return 0;
}
结果: