基本原理
递归解法的基本原理是把一个大问题拆分成几个类似的小问题,小问题继续拆解成更小的问题,直到不能拆解的单元问题为止,再把所有单元问题的解汇集成问题的全部解。就八皇后问题而言,可以先摆第一列,共八种位置选中,每种位置选择下,剩余的八行七列中继续摆放其他皇后,即变成了八个“八行七列棋盘摆七个皇后问题”的解的集合;八行七列的棋盘里面,摆第二列,剩余八行六列的棋盘,以此类推,直到最后一列摆上皇后。同样的,不仅八皇后,任意多个皇后的摆放问题都可以用这种方法求解。
代码实现
本功能采用c#来实现
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace EightQueens
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Btn_Click(object sender, EventArgs e)//控件事件
{
const string tips = "请在皇后数量处输入大于0的整数";
try
{
var queensNum = Convert.ToInt16(Text_QueensNum.Text);
if (queensNum > 0)
{
var results = EightQueens(queensNum, new List<int>());
text_ArrangeNum.Text = results.Count.ToString();
}
else
{
MessageBox.Show(tips);
}
}
catch
{
MessageBox.Show(tips);
}
}
private static List<List<int>> EightQueens(int num, ICollection<int> selectedLocation)//递归方法,num为皇后总数,selectedLocation为前面已经选定的位置
{
var results = new List<List<int>>();
if (num == 1)//皇后数为0时,一个格子,布置一个皇后
{
results.Add(new List<int> { 1 });
}
else if(num >3)//皇后数超过3时,递归
{
for (var i = 0; i < num; i++)
{
if (selectedLocation.Contains(i + 1))//前面各列摆放位置已经占用的行,跳过
{
continue;
}
var selectingLocation = selectedLocation.Select(x => x).ToList();
selectingLocation.Add(i + 1);
if (CanBeArranged(selectingLocation) == false)//判断能否布置
{
selectingLocation.Remove(selectingLocation.Last());
continue;
}
if (selectingLocation.Count == num)//全部布置完
{
results.Add(new List<int> { i + 1 });
break;
}
else//布置当前这一个皇后,同时进入下一次递归
{
results.AddRange(EightQueens(num, selectingLocation).Select(x => AddElement(i + 1, x)).ToList());//当前解的集合,等于当前皇后各摆法,对应每种摆法子问题解集的集合。
}
}
}
return results;
}
private static bool CanBeArranged(IReadOnlyList<int> resultArray)//判别能否布置,能输出true,不能输出false
{
for (var i = 0; i < resultArray.Count - 1; i++)
{
for (var j = i + 1; j < resultArray.Count; j++)
{
if (resultArray[i] + i == resultArray[j] + j || resultArray[i] - i == resultArray[j] - j)
return false;
}
}
return true;
}
private static List<T> AddElement<T>(T selectingNum, List<T> lastResult)//给List前端插入一个元素
{
lastResult.Insert(0, selectingNum);
return lastResult;
}
}
}
界面如下图所示:
用户可以在界面上输入皇后数量,在摆法总数那里查看总共摆法数量。当皇后数为8时,结果如下:
用户也可以设断点查看具体的摆法。