八皇后问题
这是一个基本而又充满趣味的题,许多人第一次接触的搜索题便是这道题,相信都给各位心灵
留下不可磨灭的印记,好了,不能再矫情了,这是要正经分享的,不能随意歪楼。下面直入正题。
定义在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。
想来大家已经耳熟能详了,乍听起来的时候感觉难顶,这是我们智能生命体该做的事吗??(结果还真是)那么解决这道题,让我们从小问题出发,对皇后的影响力进行深入分析——首先,皇后占领一块领地后,由规则产生的影响包括了横、竖、斜上、斜下的一条道都归她管理~~(说实在的管得可真宽)~~,那么对于在一个4*4的棋盘上放置4个皇后时,同样适用。缩小分析的范围,貌似这题没那么难顶了,由分析,已经很自然的想到去存储一次皇后放置后棋盘的状态,那么很自然的就可以使用多个数组进行存储。可问题的关键,怎么去建立由棋盘上的位置到数组位置的一一映射?
这时候,以前数学学的找规律该派上用场了。行列的存储都好说,就是对对角线的处理,注意到,自左下到右上的对角线上(姑且称之为右对角线),可由横纵坐标之和映射到一整条与右对角线平行的点的连线上;而在相应的左对角线上,容易想到将横坐标转换成与右对角线等同的情形即可。话不多说,上代码。代码是针对POJ上的弱化版八皇后问题,有两个预先输入标示前两行皇后所在列数。虽然弱化,但本题的核心思想未变,处理方法也是类似的。`
#include<iostream>
#include<cstring>
using namespace std;
int row[8] = { 0 }, col[8] = { 0 }, ridia[16] = { 0 }, ledia[16] = { 0 }, board[8][8] = {0};//row为行上占领情况,col为列,ridia为右对角线(自左上向右下)ledia为左对角线;
int tex[6] = { 0 },mark=0;
bool dfs(int i) //此搜索依据题目进行了相应优化,对行数依次递深搜索
{
if (i == 8) {
mark = 1;
return true;
}
for (int j = 0; j <= 7; j++) {
if (col[j] == 0 && ledia[i + j] == 0 && ridia[7 - i + j] == 0) {
col[j] = 1;
ledia[i + j] = 1;
ridia[7 - i + j] = 1;
tex[i - 2] = j;
dfs(i + 1);
if (!mark) {
col[j] = 0;
ledia[i + j] = 0;
ridia[7 - i + j] = 0;
tex[i - 2] = 0;
}
}
}
return false;
}
int main() {
int n1, n2;
cin >> n1 >> n2;
col[n1 - 1] = col[n2 - 1] = 1;
ledia[n1-1] = 1, ridia[7 + n1-1] = 1;
ledia[1 + n2-1] = 1, ridia[7 - 1 + n2-1] = 1;
dfs(2);
cout << n1 << " " << n2;
for (int i = 0; i < 6; i++)cout << " " << tex[i]+1;
return 0;
}