2018/9/23
N皇后问题:在NxN的棋盘上,放置N个棋子, 使得同一行、同一列、同一对角线上只有一个棋子,问有多少种满足条件的放置方法?
参考:1.https://blog.csdn.net/hackbuteer1/article/details/6657109 N皇后问题的两个最高效的算法
回溯法和位运算法
方法1: 【回溯法】 回溯法也叫试探法,她是一种系统地搜索问题的解的方法。
回溯法的基本思想是:从一条路往前走,能进则进,不能进则退回来,换一条路再试。
回溯法是解决一种问题的“万能算法”,这种问题是:需要将所有可能情况都穷举出来,然后从中找出满足某种要求的可能情况或最优解,从而得到整个问题的解。
/******
* 非递归方法的一个重要问题时何时回溯及如何回溯的问题。
程序首先对N行中的每一行进行探测,寻找该行中可以放置皇后的位置,具体方法是对该行的每一列进行探测,看是否可以放置皇后,
如果可以,则在该列放置一个皇后,然后继续探测下一行的皇后位置。如果已经探测完所有的列都没有找到可以放置皇后的列,
此时就应该回溯,把上一行皇后的位置往后移一列,如果上一行皇后移动后也找不到位置,则继续回溯直至某一行找到皇后的位置或回溯到第一行,
如果第一行皇后也无法找到可以放置皇后的位置,则说明已经找到所有的解程序终止。
如果该行已经是最后一行,则探测完该行后,如果找到放置皇后的位置,则说明找到一个结果,打印出来。
但是此时并不能再此处结束程序,因为我们要找的是所有N皇后问题所有的解,此时应该清除该行的皇后,从当前放置皇后列数的下一列继续探测。
*
*回溯法解N皇后问题
*使用一个一维数组表示皇后位置a[N]
*其中数组的下标表示皇后所在的行row, 数组元素值表示皇后所在的列
*这样设计的棋盘,所有皇后必定不在同一行,所以行冲突是不存在的
*********/
#include <stdio.h>
#include <iostream>
#include <math.h> //判断同一对角线上是否有冲突
using namespace std;
#define N 8 //皇后的数目
#define INIT -100 //棋盘的初始值(尽可能小的负数),因为a[i]取值从0~N-1
int a[N]; //用一维数组表示棋盘
void queue_init()
{
for (int i = 0; i < N; i++)
{
a[i] = INIT;
}
}
bool judge_queue_valid(int row, int col)
{
for (int i = 0; i < N; i++)
{
if (a[i] == col || abs(row – i) == abs(col – a[i])) //如果列冲突或者对角线冲突,则无效
{
return false;
}
}
return true;
}
int queue_core()
{
int i = 0, j = 0; //i表示row行号,j表示col列号
int n = 0; //可行的放置方案数
while (i < N)
{
while (j < N) //对i行中的每一列进行探测,看是否可以放置皇后
{
if (judge_queue_valid(i, j)) //判断放置此处是否满足N皇后条件
{
a[i] = j; //满足条件在i行j列放置皇后
j = 0; //因为下一行又要从第一列开始遍历判断,所以列清零
break; //退出内循环
}
else //i行j列这个位置不满足N皇后条件
{
j++; //继续在此行下一列探测,直到此行最后一个位置探测完自然退出内循环
}
}
//i行的所有N列已经探测完了,此处判断是否找到了满足条件的位置
if (INIT == a[i]) //如果此行没有满足条件的,则需要回溯,回溯是从后往前依次重新判断
{
if (0 == i) //i==0,回溯到最后依次:说明刚刚的内循环是在第一行中寻找满足条件的解,但是可惜没有找到
{
break; //找完了所有满足条件的解,退出大循环
}
else //不是最开始的一行,则往上回溯
{
i–; //回溯到上一行
j = a[i] + 1; //从上一次满足条件的下一个位置resume judge
a[i] = INIT; //把上一行皇后的位置清除,重新探测
continue; // 设置好j后,重新开始内循环
}
}
//如果a[i]不是初始值,则说明i行a[i]列满足条件,则继续往下执行
if ( N – 1 == i) //i探测的结果是最后一行
{
n++; //满足的方案数目
j = a[i] + 1; //从最后一行放置皇后的下一列进行回溯探测
a[i] = INIT; //清除最后一行的皇后位置
continue;
}
i++; //如果第i行满足条件,并且不是最后一行,则继续探测下一行
}//end while(i<N)
return n;
}
int main()
{
int solution_count = 0;
queue_init();
solution_count = queue_core();
cout << solution_count << endl;
system(“pause”);
return 0;
}
方法1: 【位运算法】 –未完待续。。。
位运算基本操作的意义: