前言
最近学习的过程中,不知道哪门子的思维发散,突然又遇见皇后问题了,于是乎老调重弹,心里琢磨,虽然思路大家都容易懂,哪怕是最简单的野蛮回溯法,说着简单,但是如果非得编码实现?我可以一次性写出来OK的代码吗?我对此表示疑问,于是乎动手写代码,发现写此类算法问题,最重要的是边界条件的判断。这里说明一下,这篇纯属练手,不考虑算法效率,只是为了实现,为了练习最暴力野蛮的回溯,说白了,就是怎样简单粗暴的玩弄for和while这些个玩意!
实现
本人比较懒,所以懒得搞二维数组来存储皇后坐标,其实用二维数组来存储,然后根据行列来遍历和匹配,确实效率高了不少,但是,我在这里仅仅只是练习回溯的思想,所以只是使用简单的数组来存储N*N个数,比如8皇后问题,我就用数组来存储 {1,2,3,,,,,,,,,,64},然后使用queens数组存储安全的皇后
代码
/// <summary>
/// 皇后算法非递归实现,主要思想如下:
/// 初始化皇后备选列表为空(安全),将所有坐标的棋子尝试放入
/// 如果符合安全,则放入(如果数目达到则保留输出),如果不安全则跳过继续搜索
/// 如果搜索到结尾依然未搜到,则循环向上回溯到上一次解的下一个继续
/// </summary>
public class Queen
{
// 矩阵维度
int size;
// 从1编号,存放所有整数
int[] array;
int count;
public Queen()
: this(4)
{
}
public Queen(int s)
{
this.size = s;
InitList();
}
private void InitList()
{
count = size * size;
array = new int[count];
for (int i = 0; i < count; i++)
{
array[i] = i + 1;
}
}
public void PrintQueenResult()
{
List<int> queens = new List<int>();
// 记录探测索引
int tryIndex = 0;
// 记录最后一次皇后解
int lastQueen = 0;
// 记录皇后总数
int queenCount = 0;
// 记录所有全皇后解个数
int solutions = 0;
while (true)
{
// 探测元素
int tryItem = array[tryIndex];
// 如果探测到最后一个元素,并且皇后已经回溯为空
// 表示回溯已经全部完成,返回
if (tryItem == array[count - 1] && queenCount == 0)
break;
// 找到安全的皇后
if (IsSafe(queens, tryItem))
{
queens.Add(tryItem);
// 皇后数加1
queenCount++;
// 记录最后一次放置的皇后
lastQueen = tryItem;
// 如果皇后获取足够,输出
if (queenCount == size)
{
Console.WriteLine("找到皇后排列:{0}",
string.Join(",", queens));
solutions++;
}
}
else
{
if (tryIndex < count - 1)
{
// 如果不安全,还未搜索结束,继续搜索
tryIndex++;
}
else
{
// 如果不安全,但搜索结束,则回溯
while (tryIndex >= count - 1)
{
queens.Remove(lastQueen);
queenCount--;
tryIndex = lastQueen;
// 如果回溯完毕则跳出
if (queenCount == 0)
break;
lastQueen = queens[queenCount - 1];
}
}
}
}
Console.WriteLine("全部解个数为:{0}", solutions);
}
private bool IsSafe(List<int> list, int target)
{
if (list == null || list.Count == 0)
return true;
return list.All(d => !IsDangerous(d, target));
}
private bool IsDangerous(int a, int b)
{
int rowA = (a - 1) / size + 1;
int rowB = (b - 1) / size + 1;
int colA = (a - 1) % size + 1;
int colB = (b - 1) % size + 1;
if (a == b) return true;
if (rowA == rowB) return true;
if (colA == colB) return true;
if (Math.Abs(rowA - rowB) == Math.Abs(colA - colB))
return true;
return false;
}
private int Pop(List<int> list)
{
int last = list[list.Count - 1];
list.Remove(last);
return last;
}
private int Peek(List<int> list)
{
return list[list.Count - 1];
}
}
测试
八皇后测试代码:Queen q = new Queen(8); q.PrintQueenResult();
结语
脑子不练会生锈,还是要经常做做这些最基础的东西,把不习惯变成习惯,慢慢来,不早了,先睡了