八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。
问题的内容是在国际象棋棋盘上(8*8),放置八个皇后并使其不能互相攻击。
核心在于皇后的规则:任意两个皇后都不能处于同一行、同一列或同一斜线上。
未来会重写此算法,以精简代码为目的。
已重写此算法,重写后的算法
想法是通过递归行的方式来解决问题:
第一行取八个不同的皇后位置,并依次向下递归调用第二行(即每个位置取一次)
第二行也取八个不同的皇后位置,并判断是否满足不能互相攻击的原则,满足的再次向下递归调用第三行
直到最后一行处理,满足条件的取出来即八皇后问题的解法。
使用C#实现的效果:
接下来是用C#实现的代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace test {
class Program {
const int COUNT = 8;
static int anser = 0;
static void Main(string[] args) {
Serach();
Console.WriteLine("八皇后问题的解法有: " + anser + " 种。");
Console.ReadLine();
}
/// <summary>
/// 递归-每次运行此方法都是以行为基础向下递归
/// 棋盘上以8*8的二维数组标识,有皇后为1无为0.
/// </summary>
/// <param name="chessboard"></param>
/// <param name="c"></param>
static void Serach(bool[][] chessboard = null, int c = 0)
{
bool[][] chess;
// 每次递归只运行一行
for (int i = c; i < COUNT && i < c + 1; i++) {
if (chessboard == null) // 这里方便初次调用不要输入参数
chess = new bool[COUNT][];
else
chess = chessboard; // 递归调用时拿取上一次的结果
if (chess[i] == null) { // 只有此行为NULL时才执行
for (int j = 0; j < COUNT; j++) {
chess[i] = new bool[COUNT]; // 初始化数组自动全部会赋值为false
chess[i][j] = true;
if (Check(chess)) { // 判断是否满足皇后不互相伤害的要求
if (chess[7] == null) { // 若最后一行都没有问题就可以提交了
// 数组是引用类型每一次递归都要复制一份
var temp = new bool[8][];
chess.CopyTo(temp, 0);
Serach(temp, c + 1);
} else {
anser++;
Console.WriteLine(view(chess));
}
}
}
}
}
}
/// <summary>
/// true为可取,false为不可取
/// </summary>
/// <param name="chess"></param>
/// <returns></returns>
static bool Check(bool[][] chess) {
for (int i = 0; i < COUNT; i++) {
if (chess[i] == null)
break;
for (int j = 0; j < COUNT; j++)
if (chess[i][j]) { // 判断此位置是否为皇后位置
for (int oi = 0; oi < COUNT; oi++) {
if (chess[oi] == null || oi == i)
continue; // 防止为空和重复判断一行
for (int oj = 0; oj < COUNT; oj++)
if (chess[oi][oj]) {
// 防止同列和斜列(同行的问题已经被同行递归的方式避免了)
if (j == oj || Math.Abs(oi - i) == Math.Abs(oj - j))
return false;
}
}
}
}
return true;
}
/// <summary>
/// 显示结果的方法
/// </summary>
/// <param name="chess"></param>
/// <returns></returns>
static string view(bool[][] chess) {
string str = "";
for (int i = 0; i < COUNT; i++) {
for (int j = 0; j < COUNT; j++) {
if (chess[i][j])
str += i + "行" + j + "列\n";
}
}
str += "\n=======================================";
return str;
}
}
}