算法 —— 回溯法 (N-皇后问题)
问题描述
n−皇后问题是指将 n 个皇后放在 n×n 的国际象棋棋盘上,使得皇后不能相互攻击到,即任意两个皇后都不能处于同一行、同一列或同一斜线上。
如图,假如一个皇后在Q1位置,那么打叉的位置不能放其他皇后。
求解方法
i 代表行号(要放的第几个皇后)
int[] q 表示皇后存放列号
- 按行存放(避免同行出现)
- q[i] == q[j] 列相同
- |i-j| == |q[i]-q[j]| 行相差的绝对值和列相差的绝对值相同
代码
以下代码用了两种求解
非递归求解
递归求解
namespace ConsoleApplication1
{
class Program
{
static int N = 10; //棋盘大小
int i = 1;
int answer = 0;//方案号
static int[] q = new int[N + 1];//数组记录皇后位置
/// <summary>
/// N 皇后求解(非递归方法)
/// </summary>
void queen()
{
q = new int[N + 1];
for (int n = 1; n <= 4; n++)//初始化皇后位置
{
q[n] = 0;
}
while (i >= 1)
{
q[i]++;
while (q[i] <= N && check(i))//检查是否有冲突
{
q[i]++;
}
if (q[i] <= N)//找到第i个存放位置,找下一个
{
if (i == N)//找到最后一个了
{
answer++;
Debug.Write("方案" + answer + ":");
for (int a = 1; a <= N; a++)
{
Debug.Write(q[a] + ",");
}
Debug.WriteLine("");
}
else
{
i++;
}
}
else //没有找到
{
q[i] = 0;
i--;
}
}
}
/// <summary>
/// 递归求N 皇后问题
/// </summary>
/// <param name="i"></param>
void queen2(int i)
{
for (int j = 1; j <= N; j++) //j 代表放的列号
{
q[i] = j;
if (!check(i))
{
if (i==N) //找到一个方案
{
answer++;
Debug.Write("方案" + answer + ":");
for (int a = 1; a <= N; a++)
{
Debug.Write(q[a] + ",");
}
Debug.WriteLine("");
}
else//找到i的位置 ,继续找i+1的位置
{
queen2(i + 1);
}
}
}
}
bool check(int i)
{
for (int j = 1; j < i; j++)
{
if (q[j]==q[i]||Math.Abs(i-j)==Math.Abs(q[i]-q[j]))
{
return true;
}
}
return false;
}
static void Main(string[] args)
{
Program p = new Program();
//非递归求N皇后问题
//p.queen();
//递归求N皇后问题
p.queen2(1);
}
}
}